windows-development-sandbox 1.7.0 → 1.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (432) hide show
  1. package/config.example.json +12 -1
  2. package/dist/app/context.d.ts +8 -0
  3. package/dist/app/context.js +12 -0
  4. package/dist/app/features/defs.d.ts +322 -0
  5. package/dist/app/features/defs.js +28 -0
  6. package/dist/app/features/sandbox/index.d.ts +2 -0
  7. package/dist/app/features/sandbox/index.js +3 -0
  8. package/dist/app/features/sandbox/sandbox.def.d.ts +193 -0
  9. package/dist/app/features/sandbox/sandbox.def.js +245 -0
  10. package/dist/app/features/sandbox/sandbox.run.d.ts +72 -0
  11. package/dist/app/features/sandbox/sandbox.run.js +98 -0
  12. package/dist/app/features/sessions/index.d.ts +2 -0
  13. package/dist/app/features/sessions/index.js +3 -0
  14. package/dist/app/features/sessions/sessions.def.d.ts +141 -0
  15. package/dist/app/features/sessions/sessions.def.js +176 -0
  16. package/dist/app/features/sessions/sessions.run.d.ts +39 -0
  17. package/dist/app/features/sessions/sessions.run.js +58 -0
  18. package/dist/{cli/menu/settings/categories.d.ts → app/features/settings/categories.def.d.ts} +2 -0
  19. package/dist/{cli/menu/settings/categories.js → app/features/settings/categories.def.js} +24 -5
  20. package/dist/app/features/settings/index.d.ts +5 -0
  21. package/dist/app/features/settings/index.js +6 -0
  22. package/dist/{cli/menu/settings/config-file.d.ts → app/features/settings/settings-file.d.ts} +1 -1
  23. package/dist/{cli/menu/settings/config-file.js → app/features/settings/settings-file.js} +1 -1
  24. package/dist/app/features/settings/settings-rows.d.ts +35 -0
  25. package/dist/app/features/settings/settings-rows.js +94 -0
  26. package/dist/app/features/settings/settings.def.d.ts +157 -0
  27. package/dist/app/features/settings/settings.def.js +179 -0
  28. package/dist/app/features/settings/settings.run.d.ts +67 -0
  29. package/dist/app/features/settings/settings.run.js +84 -0
  30. package/dist/app/kernel/define.d.ts +143 -0
  31. package/dist/app/kernel/define.js +42 -0
  32. package/dist/app/kernel/errors.d.ts +34 -0
  33. package/dist/app/kernel/errors.js +45 -0
  34. package/dist/app/kernel/fields.d.ts +70 -0
  35. package/dist/app/kernel/fields.js +243 -0
  36. package/dist/app/kernel/index.d.ts +8 -0
  37. package/dist/app/kernel/index.js +10 -0
  38. package/dist/app/kernel/io.d.ts +193 -0
  39. package/dist/app/kernel/io.js +126 -0
  40. package/dist/app/kernel/rpc.d.ts +156 -0
  41. package/dist/app/kernel/rpc.js +47 -0
  42. package/dist/app/kernel/text.d.ts +6 -0
  43. package/dist/app/kernel/text.js +57 -0
  44. package/dist/app/kernel/view.d.ts +146 -0
  45. package/dist/app/kernel/view.js +28 -0
  46. package/dist/app/registry.d.ts +10 -0
  47. package/dist/app/registry.js +50 -0
  48. package/dist/cli/args.d.ts +5 -0
  49. package/dist/cli/args.js +6 -0
  50. package/dist/cli/commands/engine.d.ts +2 -0
  51. package/dist/cli/commands/engine.js +60 -0
  52. package/dist/cli/commands/index.d.ts +1 -1
  53. package/dist/cli/commands/index.js +1 -1
  54. package/dist/cli/commands/launch/launch.js +49 -7
  55. package/dist/cli/commands/launch/prepare.js +3 -3
  56. package/dist/cli/commands/launch/running.js +2 -1
  57. package/dist/cli/commands/launch/summary.d.ts +2 -0
  58. package/dist/cli/commands/maintenance/config-share.d.ts +12 -0
  59. package/dist/cli/commands/maintenance/config-share.js +80 -0
  60. package/dist/cli/commands/maintenance/config.js +8 -82
  61. package/dist/cli/commands/maintenance/logs.js +14 -0
  62. package/dist/cli/commands/registry.js +3 -7
  63. package/dist/cli/commands/repair/checks/contained.d.ts +2 -0
  64. package/dist/cli/commands/repair/checks/contained.js +139 -0
  65. package/dist/cli/commands/repair/checks/hcs.d.ts +7 -0
  66. package/dist/cli/commands/repair/checks/hcs.js +28 -0
  67. package/dist/cli/commands/repair/checks/index.js +4 -0
  68. package/dist/cli/commands/repair/checks/pc.js +32 -1
  69. package/dist/cli/commands/repair/checks/sandbox.js +16 -1
  70. package/dist/cli/commands/repair/checks/vpn.js +34 -9
  71. package/dist/cli/commands/repair/env.js +2 -1
  72. package/dist/cli/commands/sessions/index.d.ts +0 -4
  73. package/dist/cli/commands/sessions/index.js +3 -7
  74. package/dist/cli/commands/shared-use.d.ts +5 -2
  75. package/dist/cli/commands/shared-use.js +11 -8
  76. package/dist/cli/commands/storage/contained.d.ts +3 -0
  77. package/dist/cli/commands/storage/contained.js +179 -0
  78. package/dist/cli/commands/storage/offer.js +7 -1
  79. package/dist/cli/commands/storage/storage.js +10 -2
  80. package/dist/cli/commands/user-config.js +1 -1
  81. package/dist/cli/commands/vpn.js +20 -3
  82. package/dist/cli/commands/web.d.ts +5 -0
  83. package/dist/cli/commands/web.js +40 -0
  84. package/dist/cli/index.js +2 -1
  85. package/dist/cli/manifest.d.ts +72 -104
  86. package/dist/cli/manifest.js +64 -39
  87. package/dist/cli/menu/add-agent.d.ts +1 -1
  88. package/dist/cli/menu/add-agent.js +1 -1
  89. package/dist/cli/menu/apps.d.ts +7 -1
  90. package/dist/cli/menu/apps.js +36 -0
  91. package/dist/cli/menu/command-fields.d.ts +1 -1
  92. package/dist/cli/menu/command-form.js +2 -2
  93. package/dist/cli/menu/io-menu.d.ts +29 -0
  94. package/dist/cli/menu/io-menu.js +126 -0
  95. package/dist/cli/menu/live.d.ts +27 -0
  96. package/dist/cli/menu/live.js +69 -0
  97. package/dist/cli/menu/memory.d.ts +19 -0
  98. package/dist/cli/menu/memory.js +53 -0
  99. package/dist/cli/menu/menu.d.ts +10 -1
  100. package/dist/cli/menu/menu.js +27 -9
  101. package/dist/cli/menu/pages/agents-page.d.ts +3 -1
  102. package/dist/cli/menu/pages/agents-page.js +12 -5
  103. package/dist/cli/menu/pages/apps-page.d.ts +3 -1
  104. package/dist/cli/menu/pages/apps-page.js +19 -2
  105. package/dist/cli/menu/pages/list-page.d.ts +27 -0
  106. package/dist/cli/menu/pages/list-page.js +109 -7
  107. package/dist/cli/menu/pages/maintenance-page.d.ts +0 -5
  108. package/dist/cli/menu/pages/maintenance-page.js +17 -19
  109. package/dist/cli/menu/pages/sandbox-page.d.ts +4 -6
  110. package/dist/cli/menu/pages/sandbox-page.js +26 -118
  111. package/dist/cli/menu/pages/scopes.d.ts +1 -1
  112. package/dist/cli/menu/pages/sessions-page.d.ts +5 -11
  113. package/dist/cli/menu/pages/sessions-page.js +19 -88
  114. package/dist/cli/menu/pages/settings-page.d.ts +2 -10
  115. package/dist/cli/menu/pages/settings-page.js +64 -94
  116. package/dist/cli/menu/render-view.d.ts +28 -0
  117. package/dist/cli/menu/render-view.js +112 -0
  118. package/dist/cli/menu/settings/{path-kind.d.ts → ask-path.d.ts} +1 -7
  119. package/dist/cli/menu/settings/ask-path.js +14 -0
  120. package/dist/cli/menu/settings/collections/collection-editor.d.ts +1 -1
  121. package/dist/cli/menu/settings/collections/string-list-editor.d.ts +1 -2
  122. package/dist/cli/menu/settings/collections/string-list-editor.js +1 -1
  123. package/dist/cli/menu/settings/draft.d.ts +1 -1
  124. package/dist/cli/menu/settings/format.d.ts +1 -3
  125. package/dist/cli/menu/settings/format.js +6 -36
  126. package/dist/cli/menu/settings/index.d.ts +1 -3
  127. package/dist/cli/menu/settings/index.js +3 -3
  128. package/dist/cli/menu/settings/object-editor.d.ts +1 -1
  129. package/dist/cli/menu/settings/share.d.ts +36 -0
  130. package/dist/cli/menu/settings/share.js +131 -0
  131. package/dist/cli/menu/settings/value-editor.d.ts +5 -1
  132. package/dist/cli/menu/settings/value-editor.js +57 -54
  133. package/dist/cli/menu/several.js +1 -1
  134. package/dist/cli/menu/share-settings.d.ts +21 -0
  135. package/dist/cli/menu/share-settings.js +112 -0
  136. package/dist/cli/menu/shell.d.ts +21 -5
  137. package/dist/cli/menu/shell.js +31 -6
  138. package/dist/cli/menu/views.d.ts +7 -0
  139. package/dist/cli/menu/views.js +11 -0
  140. package/dist/cli/menu/vpn-login.js +8 -0
  141. package/dist/cli/operations/handler.d.ts +6 -0
  142. package/dist/cli/operations/handler.js +61 -0
  143. package/dist/cli/operations/index.d.ts +4 -0
  144. package/dist/cli/operations/index.js +5 -0
  145. package/dist/cli/operations/input.d.ts +6 -0
  146. package/dist/cli/operations/input.js +37 -0
  147. package/dist/cli/operations/io-cli.d.ts +7 -0
  148. package/dist/cli/operations/io-cli.js +62 -0
  149. package/dist/cli/operations/spec.d.ts +18 -0
  150. package/dist/cli/operations/spec.js +108 -0
  151. package/dist/cli/output/colors.d.ts +2 -2
  152. package/dist/cli/output/colors.js +2 -11
  153. package/dist/cli/output/index.d.ts +1 -0
  154. package/dist/cli/output/index.js +1 -0
  155. package/dist/cli/output/print.d.ts +3 -1
  156. package/dist/cli/output/print.js +7 -3
  157. package/dist/cli/output/progress.d.ts +15 -0
  158. package/dist/cli/output/progress.js +44 -0
  159. package/dist/cli/output/render-view.d.ts +4 -0
  160. package/dist/cli/output/render-view.js +63 -0
  161. package/dist/cli/services/agent-commands-service.d.ts +2 -0
  162. package/dist/cli/services/agent-commands-service.js +11 -2
  163. package/dist/cli/services/logs-service.js +4 -3
  164. package/dist/cli/tui/app.d.ts +6 -1
  165. package/dist/cli/tui/app.js +26 -4
  166. package/dist/cli/tui/list/list-screen.d.ts +14 -0
  167. package/dist/cli/tui/list/list-screen.js +64 -36
  168. package/dist/cli/tui/list/list-types.d.ts +2 -0
  169. package/dist/cli/tui/terminal.d.ts +7 -0
  170. package/dist/cli/tui/terminal.js +30 -10
  171. package/dist/core/config/defaults.js +9 -1
  172. package/dist/core/schema/config.d.ts +14 -0
  173. package/dist/core/schema/config.js +16 -1
  174. package/dist/core/schema/harness.d.ts +1 -0
  175. package/dist/core/schema/harness.js +5 -0
  176. package/dist/core/schema/sandbox.d.ts +6 -0
  177. package/dist/core/schema/sandbox.js +20 -3
  178. package/dist/core/schema/vpn.d.ts +2 -1
  179. package/dist/core/schema/vpn.js +4 -4
  180. package/dist/core/schema/web.d.ts +1 -0
  181. package/dist/core/schema/web.js +4 -1
  182. package/dist/core/types.d.ts +23 -5
  183. package/dist/core/util/fs.d.ts +2 -0
  184. package/dist/core/util/fs.js +9 -0
  185. package/dist/core/util/index.d.ts +1 -1
  186. package/dist/core/util/index.js +1 -1
  187. package/dist/guest/agents/agent-files.d.ts +5 -0
  188. package/dist/guest/agents/agent-files.js +4 -0
  189. package/dist/guest/agents/local-state.d.ts +2 -0
  190. package/dist/guest/agents/local-state.js +21 -1
  191. package/dist/guest/boot/boot.js +5 -2
  192. package/dist/guest/daemon/daemon.js +4 -0
  193. package/dist/guest/daemon/sessions.d.ts +5 -0
  194. package/dist/guest/daemon/sessions.js +17 -3
  195. package/dist/guest/entries/daemon.js +3 -0
  196. package/dist/guest/governor/decide.d.ts +71 -0
  197. package/dist/guest/governor/decide.js +211 -0
  198. package/dist/guest/governor/governor.d.ts +45 -0
  199. package/dist/guest/governor/governor.js +230 -0
  200. package/dist/guest/governor/index.d.ts +2 -0
  201. package/dist/guest/governor/index.js +2 -0
  202. package/dist/guest/network/firewall.d.ts +1 -0
  203. package/dist/guest/network/firewall.js +65 -23
  204. package/dist/guest/runtime/csc.d.ts +1 -0
  205. package/dist/guest/runtime/csc.js +1 -0
  206. package/dist/guest/runtime/process.js +53 -5
  207. package/dist/guest/sessions/viewer.js +3 -1
  208. package/dist/guest/setup/claude-mem.js +12 -4
  209. package/dist/guest/toolchains/languages/node.js +29 -3
  210. package/dist/guest/toolchains/native/rust-extras.js +4 -2
  211. package/dist/guest/vpn/vpn.js +69 -21
  212. package/dist/guest/vpn/wireguard.d.ts +32 -0
  213. package/dist/guest/vpn/wireguard.js +132 -0
  214. package/dist/host/agent-commands/commands.d.ts +4 -0
  215. package/dist/host/agent-commands/commands.js +31 -7
  216. package/dist/host/audit/log.d.ts +1 -1
  217. package/dist/host/channel/attach.d.ts +3 -1
  218. package/dist/host/channel/attach.js +5 -2
  219. package/dist/host/channel/channel.d.ts +2 -0
  220. package/dist/host/channel/channel.js +4 -0
  221. package/dist/host/engines/engine.d.ts +12 -0
  222. package/dist/host/engines/engine.js +1 -0
  223. package/dist/host/engines/hcs/check.d.ts +25 -0
  224. package/dist/host/engines/hcs/check.js +95 -0
  225. package/dist/host/engines/hcs/documents.d.ts +44 -0
  226. package/dist/host/engines/hcs/documents.js +155 -0
  227. package/dist/host/engines/hcs/engine.d.ts +39 -0
  228. package/dist/host/engines/hcs/engine.js +171 -0
  229. package/dist/host/engines/hcs/helper.d.ts +43 -0
  230. package/dist/host/engines/hcs/helper.js +173 -0
  231. package/dist/host/engines/hcs/images.d.ts +37 -0
  232. package/dist/host/engines/hcs/images.js +152 -0
  233. package/dist/host/engines/index.d.ts +7 -0
  234. package/dist/host/engines/index.js +5 -0
  235. package/dist/host/engines/registry.d.ts +16 -0
  236. package/dist/host/engines/registry.js +30 -0
  237. package/dist/host/engines/types.d.ts +58 -0
  238. package/dist/host/engines/types.js +1 -0
  239. package/dist/host/engines/windows-sandbox/engine.d.ts +16 -0
  240. package/dist/host/engines/windows-sandbox/engine.js +63 -0
  241. package/dist/host/engines/windows-sandbox/wsb-text.d.ts +2 -0
  242. package/dist/host/engines/windows-sandbox/wsb-text.js +29 -0
  243. package/dist/host/launch/generate.d.ts +5 -1
  244. package/dist/host/launch/generate.js +50 -8
  245. package/dist/host/launch/index.d.ts +3 -1
  246. package/dist/host/launch/index.js +3 -1
  247. package/dist/host/launch/launch-plan.d.ts +13 -0
  248. package/dist/host/launch/launch-plan.js +26 -0
  249. package/dist/host/launch/mappings.js +2 -1
  250. package/dist/host/launch/risk-notes.d.ts +10 -0
  251. package/dist/host/launch/risk-notes.js +18 -0
  252. package/dist/host/launch/session-file.d.ts +2 -0
  253. package/dist/host/launch/session-file.js +7 -1
  254. package/dist/host/launch/wsb-file.d.ts +28 -4
  255. package/dist/host/launch/wsb-file.js +61 -42
  256. package/dist/host/life/crash-report.d.ts +27 -1
  257. package/dist/host/life/crash-report.js +173 -7
  258. package/dist/host/life/host-memory.d.ts +41 -0
  259. package/dist/host/life/host-memory.js +140 -0
  260. package/dist/host/life/index.d.ts +2 -0
  261. package/dist/host/life/index.js +2 -0
  262. package/dist/host/life/stop-events.d.ts +2 -0
  263. package/dist/host/life/stop-events.js +20 -3
  264. package/dist/host/life/stop-warning.js +1 -1
  265. package/dist/host/life/watchdog.d.ts +56 -0
  266. package/dist/host/life/watchdog.js +124 -0
  267. package/dist/host/native.d.ts +3 -2
  268. package/dist/host/native.js +22 -3
  269. package/dist/host/profile/claude-login.js +3 -2
  270. package/dist/host/sandbox/contained-deps.d.ts +2 -0
  271. package/dist/host/sandbox/contained-deps.js +17 -0
  272. package/dist/host/sandbox/index.d.ts +2 -0
  273. package/dist/host/sandbox/index.js +2 -0
  274. package/dist/host/sandbox/platform.d.ts +2 -0
  275. package/dist/host/sandbox/platform.js +7 -7
  276. package/dist/host/sandbox/tasklist.d.ts +13 -0
  277. package/dist/host/sandbox/tasklist.js +47 -0
  278. package/dist/host/secrets/launch-secrets.js +2 -1
  279. package/dist/host/sharing/current.js +2 -6
  280. package/dist/host/storage/contained/check.d.ts +9 -0
  281. package/dist/host/storage/contained/check.js +37 -0
  282. package/dist/host/storage/contained/contained-storage.d.ts +66 -0
  283. package/dist/host/storage/contained/contained-storage.js +168 -0
  284. package/dist/host/storage/contained/disk-port.d.ts +43 -0
  285. package/dist/host/storage/contained/disk-port.js +122 -0
  286. package/dist/host/storage/contained/index.d.ts +9 -0
  287. package/dist/host/storage/contained/index.js +8 -0
  288. package/dist/host/storage/contained/layout.d.ts +28 -0
  289. package/dist/host/storage/contained/layout.js +45 -0
  290. package/dist/host/storage/contained/resolve.d.ts +4 -0
  291. package/dist/host/storage/contained/resolve.js +30 -0
  292. package/dist/host/storage/contained/setting.d.ts +1 -0
  293. package/dist/host/storage/contained/setting.js +5 -0
  294. package/dist/host/storage/contained/state.d.ts +89 -0
  295. package/dist/host/storage/contained/state.js +166 -0
  296. package/dist/host/storage/contained/transfer.d.ts +24 -0
  297. package/dist/host/storage/contained/transfer.js +121 -0
  298. package/dist/host/storage/index.d.ts +2 -0
  299. package/dist/host/storage/index.js +2 -0
  300. package/dist/host/storage/providers/contained.d.ts +15 -0
  301. package/dist/host/storage/providers/contained.js +39 -0
  302. package/dist/host/storage/providers/folder.d.ts +12 -0
  303. package/dist/host/storage/providers/folder.js +20 -0
  304. package/dist/host/storage/providers/index.d.ts +4 -0
  305. package/dist/host/storage/providers/index.js +3 -0
  306. package/dist/host/storage/providers/registry.d.ts +9 -0
  307. package/dist/host/storage/providers/registry.js +14 -0
  308. package/dist/host/storage/providers/types.d.ts +33 -0
  309. package/dist/host/storage/providers/types.js +1 -0
  310. package/dist/host/tools/conpty.js +3 -2
  311. package/dist/host/tools/windows-terminal.js +8 -7
  312. package/dist/host/vpn/index.d.ts +1 -1
  313. package/dist/host/vpn/index.js +1 -1
  314. package/dist/host/vpn/prepare.d.ts +2 -0
  315. package/dist/host/vpn/prepare.js +63 -2
  316. package/dist/host/web/browser.d.ts +2 -0
  317. package/dist/host/web/browser.js +14 -1
  318. package/dist/host/web/index.d.ts +3 -2
  319. package/dist/host/web/index.js +3 -2
  320. package/dist/host/web/rpc.d.ts +24 -0
  321. package/dist/host/web/rpc.js +149 -0
  322. package/dist/host/web/runner.d.ts +2 -0
  323. package/dist/host/web/runner.js +1 -2
  324. package/dist/host/web/server.d.ts +7 -0
  325. package/dist/host/web/server.js +23 -3
  326. package/dist/runtime/agent.js +83 -18
  327. package/dist/runtime/daemon.js +1805 -1221
  328. package/dist/runtime/db.js +83 -18
  329. package/dist/runtime/main.js +779 -219
  330. package/dist/runtime/netproxy.js +73 -11
  331. package/dist/runtime/view.js +91 -16
  332. package/dist/selftest/agent-paths.test.js +11 -1
  333. package/dist/selftest/app.test.d.ts +2 -0
  334. package/dist/selftest/app.test.js +324 -0
  335. package/dist/selftest/channel.test.js +13 -0
  336. package/dist/selftest/cli.test.js +2 -1
  337. package/dist/selftest/config.test.js +59 -0
  338. package/dist/selftest/contained.test.d.ts +2 -0
  339. package/dist/selftest/contained.test.js +544 -0
  340. package/dist/selftest/credentials.test.js +1 -1
  341. package/dist/selftest/engine.test.d.ts +2 -0
  342. package/dist/selftest/engine.test.js +127 -0
  343. package/dist/selftest/guest-boot.test.js +47 -1
  344. package/dist/selftest/hcs.test.d.ts +2 -0
  345. package/dist/selftest/hcs.test.js +482 -0
  346. package/dist/selftest/heavy-load.test.d.ts +2 -0
  347. package/dist/selftest/heavy-load.test.js +355 -0
  348. package/dist/selftest/index.js +12 -0
  349. package/dist/selftest/layout.test.js +12 -0
  350. package/dist/selftest/menu-perf.test.d.ts +2 -0
  351. package/dist/selftest/menu-perf.test.js +248 -0
  352. package/dist/selftest/menu-screens.js +4 -2
  353. package/dist/selftest/menu.test.js +36 -8
  354. package/dist/selftest/network.test.js +20 -1
  355. package/dist/selftest/support/engine-cases.d.ts +8 -0
  356. package/dist/selftest/support/engine-cases.js +65 -0
  357. package/dist/selftest/support/engine-golden.d.ts +3 -0
  358. package/dist/selftest/support/engine-golden.js +66 -0
  359. package/dist/selftest/support/fixtures.d.ts +8 -1
  360. package/dist/selftest/support/hcs-probes.d.ts +17 -0
  361. package/dist/selftest/support/hcs-probes.js +41 -0
  362. package/dist/selftest/vpn.test.js +136 -3
  363. package/dist/selftest/web.test.js +101 -3
  364. package/dist/shared/channel/run-dir.d.ts +4 -1
  365. package/dist/shared/channel/run-dir.js +7 -1
  366. package/dist/shared/channel/schema.d.ts +35 -1
  367. package/dist/shared/channel/schema.js +27 -0
  368. package/dist/shared/channel/secrets.d.ts +1 -0
  369. package/dist/shared/channel/secrets.js +6 -0
  370. package/dist/shared/io/copy-tree.d.ts +7 -0
  371. package/dist/shared/io/copy-tree.js +45 -0
  372. package/dist/shared/io/index.d.ts +2 -0
  373. package/dist/shared/io/index.js +2 -0
  374. package/dist/shared/io/robocopy-result.d.ts +6 -0
  375. package/dist/shared/io/robocopy-result.js +23 -0
  376. package/dist/shared/memory/index.d.ts +1 -0
  377. package/dist/shared/memory/index.js +1 -0
  378. package/dist/shared/memory/policy.d.ts +38 -0
  379. package/dist/shared/memory/policy.js +63 -0
  380. package/dist/shared/network/firewall-rules.d.ts +8 -0
  381. package/dist/shared/network/firewall-rules.js +28 -0
  382. package/dist/shared/pty/output-filter.d.ts +14 -1
  383. package/dist/shared/pty/output-filter.js +22 -4
  384. package/dist/shared/pty/terminal.d.ts +4 -1
  385. package/dist/shared/pty/terminal.js +4 -2
  386. package/dist/shared/system.d.ts +1 -0
  387. package/dist/shared/system.js +1 -0
  388. package/dist/shared/vpn/download.d.ts +16 -0
  389. package/dist/shared/vpn/download.js +16 -0
  390. package/dist/shared/vpn/wireguard.d.ts +51 -0
  391. package/dist/shared/vpn/wireguard.js +227 -0
  392. package/dist/sync/sync-cycle.js +5 -5
  393. package/dist/sync/watcher.d.ts +13 -0
  394. package/dist/sync/watcher.js +92 -3
  395. package/dist/web/index.html +4 -3
  396. package/dist/web/main-NRRS5O6Z.js +157 -0
  397. package/dist/web/main-T5DMCHYV.css +1 -0
  398. package/native/csharp/HcsHost/AssemblyInfo.cs +14 -0
  399. package/native/csharp/HcsHost/Guard.cs +100 -0
  400. package/native/csharp/HcsHost/Hcs.cs +256 -0
  401. package/native/csharp/HcsHost/Json.cs +78 -0
  402. package/native/csharp/HcsHost/Program.cs +185 -0
  403. package/native/csharp/HcsHost/VirtualDisk.cs +95 -0
  404. package/native/csharp/HostTools/AssemblyInfo.cs +14 -0
  405. package/native/csharp/HostTools/MemoryStatus.cs +128 -0
  406. package/native/csharp/HostTools/Program.cs +58 -17
  407. package/native/scripts/check-contained.ps1 +28 -0
  408. package/native/scripts/contained-common.ps1 +241 -0
  409. package/native/scripts/dismount-contained.ps1 +66 -0
  410. package/native/scripts/memory-status.ps1 +42 -0
  411. package/native/scripts/mount-contained.ps1 +139 -0
  412. package/native/scripts/run-elevated.ps1 +17 -4
  413. package/native/scripts/stop-events.ps1 +23 -8
  414. package/package.json +9 -2
  415. package/sandbox/csharp/MemGov.cs +466 -0
  416. package/sandbox/csharp/PtyHost.cs +111 -5
  417. package/sandbox/scripts/new-shortcuts.ps1 +3 -1
  418. package/schemas/config.schema.json +66 -8
  419. package/schemas/sandbox-config.schema.json +3 -3
  420. package/dist/cli/commands/sessions/control.d.ts +0 -4
  421. package/dist/cli/commands/sessions/control.js +0 -66
  422. package/dist/cli/commands/sessions/list.d.ts +0 -2
  423. package/dist/cli/commands/sessions/list.js +0 -48
  424. package/dist/cli/commands/sessions/status.d.ts +0 -4
  425. package/dist/cli/commands/sessions/status.js +0 -114
  426. package/dist/cli/commands/sessions/window.d.ts +0 -3
  427. package/dist/cli/commands/sessions/window.js +0 -18
  428. package/dist/cli/menu/settings/path-kind.js +0 -44
  429. package/dist/web/main-CXESL347.js +0 -45
  430. package/dist/web/main-VLR7DVQ4.css +0 -1
  431. /package/dist/{cli/menu/settings → app/kernel}/schema-node.d.ts +0 -0
  432. /package/dist/{cli/menu/settings → app/kernel}/schema-node.js +0 -0
@@ -1,6 +1,16 @@
1
1
  // The common shape of a tab that is a list: it loads its data, builds a list screen from it, and acts on what the list
2
- // returns. After every action the list is built again from fresh data, on the same entry.
2
+ // returns. After every action the list is built again from fresh data, on the same entry. Opening a tab never makes
3
+ // the keys wait for a slow load: after a moment the tab shows "Loading…" (or the data it had), and the list is built
4
+ // when the data is there.
3
5
  import { ListScreen, } from '../../tui/index.js';
6
+ import { errMsg } from '../../../core/util/index.js';
7
+ import { Theme } from '../../tui/index.js';
8
+ /** A tab whose data is not here after this long shows "Loading…" instead of holding up the keys. */
9
+ const QUICK_LOAD_MS = 120;
10
+ /** What a tab shows before its data has arrived. */
11
+ function loadingOptions() {
12
+ return { path: [], items: [], empty: 'Loading…' };
13
+ }
4
14
  export class ListPage {
5
15
  app;
6
16
  stages = false;
@@ -10,6 +20,14 @@ export class ListPage {
10
20
  focused = true;
11
21
  /** The entry that was last acted on: the cursor returns to it when the section opens again. */
12
22
  lastFocus;
23
+ /** A search to start the next list with (restored from the last run); used once. */
24
+ pendingQuery;
25
+ /** The data has arrived at least once (until then the list is "Loading…"). */
26
+ loaded = false;
27
+ /** Counts loads, so that a slow one that was overtaken does not replace newer data. */
28
+ generation = 0;
29
+ /** A category asked for before the data arrived: it opens when it does. */
30
+ wantedCategory;
13
31
  constructor(app) {
14
32
  this.app = app;
15
33
  }
@@ -17,6 +35,10 @@ export class ListPage {
17
35
  initialFocus() {
18
36
  return undefined;
19
37
  }
38
+ /** The data has not arrived yet (the tab shows "Loading…"). */
39
+ get loading() {
40
+ return !this.loaded;
41
+ }
20
42
  get capturing() {
21
43
  return this.list?.isSearching ?? false;
22
44
  }
@@ -24,10 +46,24 @@ export class ListPage {
24
46
  get category() {
25
47
  return this.list?.currentCategory;
26
48
  }
49
+ /** The search typed in the list ('' when none). */
50
+ get search() {
51
+ return this.list?.searchText ?? '';
52
+ }
53
+ /** Shows the list with this search typed (the menu opens on the search it was left on). */
54
+ restoreSearch(text) {
55
+ this.pendingQuery = text;
56
+ if (this.loaded)
57
+ this.rebuild(undefined);
58
+ }
27
59
  categories() {
28
60
  return this.screen().categories;
29
61
  }
30
62
  async selectCategory(id) {
63
+ if (!this.loaded) {
64
+ this.wantedCategory = id;
65
+ return;
66
+ }
31
67
  this.screen().setCategory(id);
32
68
  await this.afterKey();
33
69
  }
@@ -41,7 +77,15 @@ export class ListPage {
41
77
  }
42
78
  /** A list from the current data; its categories are shown by the menu's navigation. */
43
79
  build(extra) {
44
- const list = new ListScreen({ ...this.options(), ...extra, categoryNav: 'external', escapeLabel: 'sections' });
80
+ const startQuery = this.pendingQuery;
81
+ this.pendingQuery = undefined;
82
+ const list = new ListScreen({
83
+ ...(this.loaded ? this.options() : loadingOptions()),
84
+ startQuery,
85
+ ...extra,
86
+ categoryNav: 'external',
87
+ escapeLabel: 'sections',
88
+ });
45
89
  list.setActive(this.focused);
46
90
  return list;
47
91
  }
@@ -49,14 +93,68 @@ export class ListPage {
49
93
  ticked() {
50
94
  return this.list?.ticked() ?? [];
51
95
  }
96
+ /** Loads the data again; a slow load does not hold up the keys (the tab keeps what it showed, then updates). */
52
97
  async open() {
53
- await this.load();
54
- // Back on the entry used last, when it is still in the category that is open.
55
- const wanted = this.lastFocus ?? this.initialFocus();
98
+ await this.reload(true);
99
+ }
100
+ /**
101
+ * Loads the data and waits for it at most QUICK_LOAD_MS. In time, the list is built here (`build`) or by the caller;
102
+ * later, the list is built when the data arrives, on the entry and search the user has moved to meanwhile.
103
+ */
104
+ async reload(build) {
105
+ const mine = ++this.generation;
106
+ let late = false;
107
+ let timer;
108
+ const quick = new Promise((resolve) => {
109
+ timer = setTimeout(() => {
110
+ late = true;
111
+ resolve();
112
+ }, QUICK_LOAD_MS);
113
+ });
114
+ const arrived = this.loadData().then(() => {
115
+ if (mine !== this.generation)
116
+ return;
117
+ this.loaded = true;
118
+ if (late)
119
+ this.rebuildLate();
120
+ else if (build)
121
+ this.rebuildOpened();
122
+ });
123
+ await Promise.race([arrived, quick]);
124
+ clearTimeout(timer);
125
+ }
126
+ async loadData() {
127
+ try {
128
+ await this.load();
129
+ }
130
+ catch (e) {
131
+ this.say(Theme.error(Theme.glyph.cross + ' ' + errMsg(e)));
132
+ }
133
+ }
134
+ /** Back on the entry used last, when it is still in the category that is open. */
135
+ rebuildOpened() {
136
+ this.rebuildOn(this.lastFocus ?? this.initialFocus());
137
+ this.openWantedCategory();
138
+ }
139
+ /** Data that came after the keys stopped waiting: the cursor and the search stay where the user moved them. */
140
+ rebuildLate() {
141
+ if (this.list)
142
+ this.pendingQuery ??= this.list.searchText || undefined;
143
+ this.rebuildOn(this.list?.current);
144
+ this.openWantedCategory();
145
+ this.app.requestRedraw();
146
+ }
147
+ rebuildOn(wanted) {
56
148
  const open = this.list?.currentCategory;
57
149
  const item = wanted === undefined ? undefined : this.options().items.find((i) => i.value === wanted);
58
150
  this.rebuild(item && (!open || !item.category || item.category === open) ? wanted : undefined);
59
151
  }
152
+ openWantedCategory() {
153
+ if (!this.wantedCategory)
154
+ return;
155
+ this.list?.setCategory(this.wantedCategory);
156
+ this.wantedCategory = undefined;
157
+ }
60
158
  /** Builds the list again, on `focus` when it is still there. */
61
159
  rebuild(focus, notice) {
62
160
  const startCategory = this.list?.currentCategory;
@@ -83,8 +181,12 @@ export class ListPage {
83
181
  const outcome = result.kind === 'back' ? { exit: { kind: 'quit' } } : await this.act(result);
84
182
  if (outcome.exit)
85
183
  return { done: outcome.exit };
86
- if (outcome.reload)
87
- await this.load();
184
+ // What the action changed (a stop, a restart) is known to the menu before the page loads again. An action that
185
+ // loads nothing again changed nothing the menu shows, so the keys do not wait for it.
186
+ if (outcome.reload) {
187
+ await this.app.afterAction();
188
+ await this.reload(false);
189
+ }
88
190
  const here = result.kind === 'pick' || result.kind === 'action' ? result.value : undefined;
89
191
  this.lastFocus = outcome.focus ?? here ?? this.lastFocus;
90
192
  this.rebuild(outcome.focus ?? here, outcome.notice);
@@ -4,8 +4,6 @@ import { type DataEntry } from '../../commands/data/collect.js';
4
4
  import type { RepairResult } from '../../commands/repair/types.js';
5
5
  import { type LogFile, type SetupReport, type UpdateStatus } from '../../services/index.js';
6
6
  import { type App, type ListOptions, type ListResult } from '../../tui/index.js';
7
- import type { Step } from '../../tui/index.js';
8
- import type { ShellExit } from '../shell.js';
9
7
  import { ListPage, type Outcome } from './list-page.js';
10
8
  export interface MaintenanceModel {
11
9
  /** The data folder row (where the sandbox keeps its data). */
@@ -54,7 +52,6 @@ export declare class MaintenancePage extends ListPage<string> {
54
52
  private doctorRows;
55
53
  private repairRows;
56
54
  private setupReport;
57
- private seen;
58
55
  private settings;
59
56
  private readonly migrate;
60
57
  private readonly health;
@@ -65,8 +62,6 @@ export declare class MaintenancePage extends ListPage<string> {
65
62
  private model;
66
63
  protected load(): Promise<void>;
67
64
  protected options(): ListOptions<string>;
68
- /** Opening a category loads what it shows (the cheap ones; data is measured on request). */
69
- protected afterKey(): Promise<Step<ShellExit>>;
70
65
  private readSettings;
71
66
  private updateStatus;
72
67
  /** The Updates category: look, install, go back, switch automatic updates. */
@@ -148,6 +148,18 @@ export function maintenanceOptions(m) {
148
148
  hint: humanBytes(f.bytes) + ' ' + ago(f.modified),
149
149
  description: 'Enter shows the end of this log in the terminal.',
150
150
  }));
151
+ // The checks take seconds (programs are run), so they are not made while you move through the categories.
152
+ const check = m.doctor === null && m.setup === null
153
+ ? [
154
+ {
155
+ value: 'health:check',
156
+ label: 'Check this PC',
157
+ category: 'health',
158
+ section: 'Doctor',
159
+ description: 'Looks at this PC: Windows features, the install, the folders and the sandbox. It takes a few seconds, so it only runs when you ask.',
160
+ },
161
+ ]
162
+ : [];
151
163
  const doctor = (m.doctor ?? []).map(([name, detail], i) => ({
152
164
  value: 'doctor:' + i,
153
165
  label: name,
@@ -225,7 +237,7 @@ export function maintenanceOptions(m) {
225
237
  return {
226
238
  path: [],
227
239
  categories: CATEGORIES,
228
- items: [...updates, ...settings, ...dataItems(m), ...doctor, ...repair, ...setup, ...logs, ...more],
240
+ items: [...updates, ...settings, ...dataItems(m), ...check, ...doctor, ...repair, ...setup, ...logs, ...more],
229
241
  empty: 'Nothing here yet.',
230
242
  actions: maintenanceActions(m),
231
243
  enterLabel: (_category, id) => enterLabel(id ?? '', m),
@@ -241,6 +253,8 @@ function enterLabel(id, m) {
241
253
  return 'choose what';
242
254
  if (id === 'repair:run')
243
255
  return 'check and fix';
256
+ if (id === 'health:check')
257
+ return 'check';
244
258
  if (id === 'updates:latest')
245
259
  return m.latest ? 'install' : 'look';
246
260
  if (id === 'updates:auto')
@@ -271,7 +285,7 @@ function maintenanceActions(m) {
271
285
  const canEnable = m.setup !== null && !('error' in m.setup) && m.setup.canEnable;
272
286
  return [
273
287
  { key: 'f', label: 'check and fix' },
274
- { key: 'l', label: 'check again' },
288
+ { key: 'l', label: m.doctor ? 'check again' : 'check' },
275
289
  ...(canEnable ? [{ key: 'e', label: 'turn on Windows Sandbox' }] : []),
276
290
  ];
277
291
  }
@@ -313,7 +327,6 @@ export class MaintenancePage extends ListPage {
313
327
  doctorRows = null;
314
328
  repairRows = null;
315
329
  setupReport = null;
316
- seen;
317
330
  settings = { pending: [] };
318
331
  migrate;
319
332
  health;
@@ -362,21 +375,6 @@ export class MaintenancePage extends ListPage {
362
375
  options() {
363
376
  return maintenanceOptions(this.model());
364
377
  }
365
- /** Opening a category loads what it shows (the cheap ones; data is measured on request). */
366
- async afterKey() {
367
- const category = this.category;
368
- if (category === this.seen)
369
- return;
370
- this.seen = category;
371
- if (category !== 'health' || (this.doctorRows && this.setupReport))
372
- return;
373
- if (!this.doctorRows)
374
- await this.loadDoctor();
375
- if (!this.setupReport)
376
- await this.loadSetup();
377
- this.rebuild(undefined);
378
- return;
379
- }
380
378
  readSettings() {
381
379
  try {
382
380
  this.settings = { pending: this.migrate.plan() };
@@ -493,7 +491,7 @@ export class MaintenancePage extends ListPage {
493
491
  if (this.category === 'health') {
494
492
  if (key === 'f' || id === 'repair:run')
495
493
  return this.repair();
496
- if (key === 'l') {
494
+ if (key === 'l' || id === 'health:check') {
497
495
  await this.loadDoctor();
498
496
  await this.loadSetup();
499
497
  return {};
@@ -1,9 +1,10 @@
1
+ import { type SandboxStatus } from '../../../app/features/sandbox/index.js';
1
2
  import type { Context } from '../../commands/context.js';
2
- import { type DatabaseRow, type ProjectsListing, type SandboxReport } from '../../services/index.js';
3
+ import { type DatabaseRow, type ProjectsListing } from '../../services/index.js';
3
4
  import { type App, type ListOptions, type ListResult } from '../../tui/index.js';
4
5
  import { ListPage, type Outcome } from './list-page.js';
5
6
  export interface SandboxModel {
6
- readonly report: SandboxReport;
7
+ readonly report: SandboxStatus;
7
8
  readonly projects: ProjectsListing;
8
9
  /** Null: the sandbox is not running or did not answer. */
9
10
  readonly databases: DatabaseRow[] | null;
@@ -16,8 +17,8 @@ export declare class SandboxPage extends ListPage<string> {
16
17
  private readonly ctx;
17
18
  readonly label = "Sandbox";
18
19
  private model;
19
- private readonly sandbox;
20
20
  private readonly projects;
21
+ private readonly operations;
21
22
  constructor(app: App, ctx: Context);
22
23
  protected load(): Promise<void>;
23
24
  /** The folder `sbx-db` runs in: the sandbox's own workspace. */
@@ -26,9 +27,6 @@ export declare class SandboxPage extends ListPage<string> {
26
27
  protected act(result: ListResult<string>): Promise<Outcome<string>>;
27
28
  private defaultAgent;
28
29
  private noSandbox;
29
- private show;
30
- private hide;
31
- private stop;
32
30
  private addRoot;
33
31
  private forget;
34
32
  private toggleDatabase;
@@ -1,12 +1,15 @@
1
- // Section 3: the sandbox as a whole. Status (a card, the window, stopping it), Projects (roots and known projects) and
2
- // Databases (start and stop), each a category on the left.
1
+ // Section 3: the sandbox as a whole. Status (the sandbox view: its facts, the window, stopping it), Projects (roots and
2
+ // known projects) and Databases (start and stop), each a category on the left.
3
3
  import fs from 'node:fs';
4
4
  import path from 'node:path';
5
+ import { sandboxPage, sandboxStatus } from '../../../app/features/sandbox/index.js';
6
+ import { readQuery } from '../../../app/registry.js';
5
7
  import { errMsg, safeText } from '../../../core/util/index.js';
6
8
  import { RunDir } from '../../../shared/channel/index.js';
7
- import { ago } from '../../output/index.js';
8
- import { DatabasesService, ProjectsService, SandboxService, } from '../../services/index.js';
9
+ import { DatabasesService, ProjectsService } from '../../services/index.js';
9
10
  import { Text, Theme, } from '../../tui/index.js';
11
+ import { MenuOperations } from '../io-menu.js';
12
+ import { menuView } from '../render-view.js';
10
13
  import { ListPage } from './list-page.js';
11
14
  const CATEGORIES = [
12
15
  { id: 'status', label: 'Status', description: 'What the sandbox is doing, its window, and stopping it.' },
@@ -17,51 +20,15 @@ const CATEGORIES = [
17
20
  },
18
21
  { id: 'databases', label: 'Databases', description: 'Databases the sandbox can run: start and stop them.' },
19
22
  ];
20
- const yesNo = (v) => (v === undefined ? '-' : v ? 'yes' : 'no');
23
+ /** The status category: the sandbox view's rows (prefixed, so they never clash with the projects' rows). */
24
+ function statusView(m) {
25
+ return menuView(sandboxPage(m.report), { category: 'status', prefix: 'status:', refresh: false });
26
+ }
21
27
  /** The list for the sandbox tab. Pure. */
22
28
  export function sandboxOptions(m) {
23
- const { sandbox, repoGuard } = m.report;
24
- const running = sandbox.running;
25
- const row = (id, label, hint, extra = {}) => ({
26
- value: id,
27
- label,
28
- hint,
29
- category: 'status',
30
- section: 'Sandbox',
31
- ...extra,
32
- });
33
- const sessions = m.report.projects.reduce((n, p) => n + p.sessions.length, 0) + m.report.otherSessions.length;
34
- const status = [
35
- ...(running ? [] : startRows(m.defaultAgent, 'status')),
36
- row('info:state', 'State', running ? Theme.ok(Theme.glyph.on + ' ' + sandbox.phase) : Theme.muted(Theme.glyph.off + ' stopped'), { description: sandbox.message ? safeText(sandbox.message) : undefined }),
37
- row('info:uptime', 'Up for', sandbox.startedAt && running ? ago(sandbox.startedAt).replace(' ago', '') : '-'),
38
- row('info:daemon', 'Sandbox agent', running ? safeText(sandbox.daemon) : '-'),
39
- row('info:window', 'Window', running ? (sandbox.headless ? 'hidden' : 'shown') : '-'),
40
- row('info:sessions', 'Sessions', running ? String(sessions) : '-'),
41
- row('info:account', 'Claude account', sandbox.account ?? '-'),
42
- row('info:sync', 'History sync running', yesNo(sandbox.syncWatcher)),
43
- row('info:guard', 'Repo guard', repoGuard.guarded +
44
- ' folder(s) guarded' +
45
- (repoGuard.findings.length ? ', ' + repoGuard.findings.length + ' change(s) neutralised' : ''), {
46
- details: repoGuard.findings.slice(-8).map((f) => Theme.warn(safeText(f))),
47
- }),
48
- ...(running
49
- ? [
50
- row('act:show', 'Show the window', '', {
51
- section: 'Actions',
52
- description: 'Brings the sandbox window to the front.',
53
- }),
54
- row('act:hide', 'Hide the window', '', {
55
- section: 'Actions',
56
- description: 'Hides the window. Show the window brings it back.',
57
- }),
58
- row('act:stop', 'Stop the sandbox…', '', {
59
- section: 'Actions',
60
- description: 'Shuts the sandbox down; your history syncs back when it closes.',
61
- }),
62
- ]
63
- : []),
64
- ];
29
+ const running = m.report.sandbox.running;
30
+ const status = statusView(m);
31
+ const statusItems = [...(running ? [] : startRows(m.defaultAgent, 'status')), ...status.items];
65
32
  const addRoot = {
66
33
  value: ADD_ROOT,
67
34
  label: '+ Add a project root…',
@@ -113,11 +80,11 @@ export function sandboxOptions(m) {
113
80
  }));
114
81
  return {
115
82
  path: [],
116
- items: [...status, addRoot, ...roots, ...projects, ...databases, ...noDatabases],
83
+ items: [...statusItems, addRoot, ...roots, ...projects, ...databases, ...noDatabases],
117
84
  categories: CATEGORIES,
118
85
  empty: 'Nothing here yet.',
119
- actions: (category) => sandboxActions(category, running),
120
- enterLabel: (_category, id) => enterLabel(id ?? '', m),
86
+ actions: (category) => category === 'projects' || category === 'databases' ? sandboxActions(category) : [...status.actions, REFRESH],
87
+ enterLabel: (category, id) => status.enterLabel(category, id) || enterLabel(id ?? '', m),
121
88
  };
122
89
  }
123
90
  const ADD_ROOT = '@add-root';
@@ -142,14 +109,8 @@ function startRows(agent, category) {
142
109
  },
143
110
  ];
144
111
  }
145
- /** What Enter does on a row ("" = the row only shows information). */
112
+ /** What Enter does on a row of Projects and Databases ("" = the row only shows information). */
146
113
  function enterLabel(id, m) {
147
- if (id === 'act:show')
148
- return 'show';
149
- if (id === 'act:hide')
150
- return 'hide';
151
- if (id === 'act:stop')
152
- return 'stop';
153
114
  if (id.startsWith('act:start'))
154
115
  return 'start';
155
116
  if (id === ADD_ROOT)
@@ -158,7 +119,7 @@ function enterLabel(id, m) {
158
119
  return m.databases?.find((d) => 'db:' + d.name === id)?.running ? 'stop' : 'start';
159
120
  return '';
160
121
  }
161
- function sandboxActions(category, running) {
122
+ function sandboxActions(category) {
162
123
  if (category === 'projects')
163
124
  return [
164
125
  { key: 'a', label: 'add root', importance: 1 },
@@ -166,31 +127,22 @@ function sandboxActions(category, running) {
166
127
  { key: 'f', label: 'forget project', importance: 1, applies: (id) => id.startsWith('project:') },
167
128
  REFRESH,
168
129
  ];
169
- if (category === 'databases')
170
- return [REFRESH];
171
- return running
172
- ? [
173
- { key: 'w', label: 'show window', importance: 3 },
174
- { key: 'h', label: 'hide window', importance: 3 },
175
- { key: 'x', label: 'stop', importance: 1 },
176
- REFRESH,
177
- ]
178
- : [REFRESH];
130
+ return [REFRESH];
179
131
  }
180
132
  export class SandboxPage extends ListPage {
181
133
  ctx;
182
134
  label = 'Sandbox';
183
135
  model;
184
- sandbox;
185
136
  projects;
137
+ operations;
186
138
  constructor(app, ctx) {
187
139
  super(app);
188
140
  this.ctx = ctx;
189
- this.sandbox = new SandboxService(ctx);
190
141
  this.projects = new ProjectsService(ctx);
142
+ this.operations = new MenuOperations(app, ctx);
191
143
  }
192
144
  async load() {
193
- const report = await this.sandbox.status();
145
+ const report = await readQuery(sandboxStatus, this.ctx);
194
146
  const guest = report.sandbox.running && report.sandbox.phase === 'ready' ? this.guestWorkspace() : null;
195
147
  let databases = null;
196
148
  if (guest) {
@@ -218,18 +170,15 @@ export class SandboxPage extends ListPage {
218
170
  try {
219
171
  if (key === 'l')
220
172
  return { reload: true };
173
+ const chosen = this.model ? statusView(this.model).resolve(result) : undefined;
174
+ if (chosen?.kind === 'action')
175
+ return await this.operations.perform(chosen.action, [this.label], (text) => this.busy(text, id));
221
176
  if (id === 'act:start' && !key)
222
177
  return { exit: { kind: 'run', argv: ['launch', '--harness', this.defaultAgent()] } };
223
178
  if (id === 'act:start-bare' && !key)
224
179
  return { exit: { kind: 'run', argv: ['start'] } };
225
180
  if (id === ADD_ROOT && !key)
226
181
  return await this.addRoot();
227
- if (id === 'act:show' || key === 'w')
228
- return this.show();
229
- if (id === 'act:hide' || key === 'h')
230
- return await this.hide();
231
- if (id === 'act:stop' || key === 'x')
232
- return await this.stop();
233
182
  if (key === 'a')
234
183
  return await this.addRoot();
235
184
  if (key === 'f')
@@ -248,47 +197,6 @@ export class SandboxPage extends ListPage {
248
197
  noSandbox() {
249
198
  return this.model?.report.sandbox.running ? null : { notice: Theme.warn('No sandbox is running.') };
250
199
  }
251
- show() {
252
- const none = this.noSandbox();
253
- if (none)
254
- return none;
255
- this.sandbox.showWindow();
256
- return { notice: Theme.ok(Theme.glyph.ok + ' Window shown.') };
257
- }
258
- async hide() {
259
- const none = this.noSandbox();
260
- if (none)
261
- return none;
262
- await this.sandbox.hideWindow();
263
- return {
264
- reload: true,
265
- notice: Theme.ok(Theme.glyph.ok + ' Window hidden.'),
266
- };
267
- }
268
- async stop() {
269
- const none = this.noSandbox();
270
- if (none)
271
- return none;
272
- const plan = this.sandbox.stopPlan();
273
- const named = plan.running.map((s) => safeText(s.harness) + ' in ' + safeText(s.project ?? path.win32.basename(s.cwd)));
274
- const lines = [
275
- plan.running.length
276
- ? 'Stopping ends ' +
277
- plan.running.length +
278
- ' session' +
279
- (plan.running.length === 1 ? '' : 's') +
280
- ': ' +
281
- named.join(', ') +
282
- '.'
283
- : 'No session is running.',
284
- ...(plan.others.length ? [plan.others.length + ' of them belong to other projects.'] : []),
285
- 'History and claude-mem sync back when it closes.',
286
- ];
287
- if (!(await this.app.ask('Stop the sandbox?', lines, 'Stop', true)))
288
- return {};
289
- await this.sandbox.shutdown(plan.sandbox);
290
- return { reload: true, notice: Theme.ok(Theme.glyph.ok + ' The sandbox is shutting down.') };
291
- }
292
200
  async addRoot() {
293
201
  const picked = await this.app.pickPath({
294
202
  path: ['Sandbox', 'Add a project root'],
@@ -1,5 +1,5 @@
1
1
  import { type Tab } from '../../tui/index.js';
2
- import type { ConfigFile } from '../settings/config-file.js';
2
+ import type { ConfigFile } from '../../../app/features/settings/index.js';
3
3
  export type Scope = 'user' | 'project';
4
4
  export declare const SCOPES: {
5
5
  scope: Scope;
@@ -1,23 +1,17 @@
1
+ import { type SessionsList } from '../../../app/features/sessions/index.js';
1
2
  import type { Context } from '../../commands/context.js';
2
- import { type ListedSession } from '../../services/index.js';
3
- import { type App, type ListOptions, type ListResult } from '../../tui/index.js';
3
+ import type { App, ListOptions, ListResult } from '../../tui/index.js';
4
4
  import { ListPage, type Outcome } from './list-page.js';
5
- export interface SessionsModel {
6
- readonly sandboxRunning: boolean;
7
- /** Newest first, this folder's project first. */
8
- readonly sessions: readonly ListedSession[];
9
- /** The agent "Start" offers while there is no session. */
10
- readonly defaultAgent: string;
11
- }
5
+ /** What the page shows: the sessions query's result (the folder column is never shown here). */
6
+ export type SessionsModel = Omit<SessionsList, 'wide'>;
12
7
  /** The list for the sessions tab. Pure. */
13
8
  export declare function sessionsOptions(m: SessionsModel): ListOptions<string>;
14
9
  export declare class SessionsPage extends ListPage<string> {
15
10
  private readonly ctx;
16
11
  readonly label = "Sessions";
17
12
  private model;
18
- private readonly service;
13
+ private readonly operations;
19
14
  constructor(app: App, ctx: Context);
20
- private defaultAgent;
21
15
  protected load(): Promise<void>;
22
16
  protected options(): ListOptions<string>;
23
17
  protected act(result: ListResult<string>): Promise<Outcome<string>>;