windows-development-sandbox 1.0.5 → 1.4.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 (453) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +25 -8
  3. package/config.example.json +55 -5
  4. package/dist/api.js +2 -1
  5. package/dist/cli/args.d.ts +23 -0
  6. package/dist/cli/args.js +38 -4
  7. package/dist/cli/colors.d.ts +24 -0
  8. package/dist/cli/colors.js +42 -0
  9. package/dist/cli/commands/accounts.js +2 -2
  10. package/dist/cli/commands/agent-commands.d.ts +6 -0
  11. package/dist/cli/commands/agent-commands.js +61 -0
  12. package/dist/cli/commands/context.d.ts +2 -0
  13. package/dist/cli/commands/context.js +5 -1
  14. package/dist/cli/commands/data/clean.d.ts +15 -0
  15. package/dist/cli/commands/data/clean.js +106 -0
  16. package/dist/cli/commands/data/collect.d.ts +11 -0
  17. package/dist/cli/commands/data/collect.js +54 -0
  18. package/dist/cli/commands/data/index.d.ts +4 -0
  19. package/dist/cli/commands/data/index.js +45 -0
  20. package/dist/cli/commands/data/remove.d.ts +2 -0
  21. package/dist/cli/commands/data/remove.js +30 -0
  22. package/dist/cli/commands/index.d.ts +6 -4
  23. package/dist/cli/commands/index.js +6 -4
  24. package/dist/cli/commands/launch.d.ts +26 -2
  25. package/dist/cli/commands/launch.js +256 -42
  26. package/dist/cli/commands/maintenance.d.ts +2 -0
  27. package/dist/cli/commands/maintenance.js +67 -5
  28. package/dist/cli/commands/project.d.ts +29 -0
  29. package/dist/cli/commands/project.js +63 -0
  30. package/dist/cli/commands/projects.d.ts +14 -0
  31. package/dist/cli/commands/projects.js +146 -0
  32. package/dist/cli/commands/repair/checks.d.ts +2 -0
  33. package/dist/cli/commands/{repair.js → repair/checks.js} +19 -181
  34. package/dist/cli/commands/{repair.d.ts → repair/finders.d.ts} +0 -29
  35. package/dist/cli/commands/repair/finders.js +108 -0
  36. package/dist/cli/commands/repair/index.d.ts +12 -0
  37. package/dist/cli/commands/repair/index.js +61 -0
  38. package/dist/cli/commands/repair/types.d.ts +26 -0
  39. package/dist/cli/commands/repair/types.js +3 -0
  40. package/dist/cli/commands/restart.d.ts +6 -0
  41. package/dist/cli/commands/restart.js +85 -0
  42. package/dist/cli/commands/sessions.d.ts +2 -1
  43. package/dist/cli/commands/sessions.js +189 -45
  44. package/dist/cli/commands/setup/checks.d.ts +13 -0
  45. package/dist/cli/commands/setup/checks.js +71 -0
  46. package/dist/cli/commands/{setup.d.ts → setup/facts.d.ts} +1 -15
  47. package/dist/cli/commands/setup/facts.js +60 -0
  48. package/dist/cli/commands/setup/index.d.ts +2 -0
  49. package/dist/cli/commands/setup/index.js +43 -0
  50. package/dist/cli/commands/user-config.d.ts +8 -0
  51. package/dist/cli/commands/user-config.js +41 -0
  52. package/dist/cli/history.d.ts +11 -0
  53. package/dist/cli/history.js +21 -0
  54. package/dist/cli/index.d.ts +7 -1
  55. package/dist/cli/index.js +42 -15
  56. package/dist/cli/manifest.d.ts +8 -0
  57. package/dist/cli/manifest.js +40 -15
  58. package/dist/cli/menu/apps.d.ts +21 -0
  59. package/dist/cli/menu/apps.js +122 -0
  60. package/dist/cli/menu/command-form.d.ts +28 -0
  61. package/dist/cli/menu/command-form.js +219 -0
  62. package/dist/cli/menu/index.d.ts +26 -0
  63. package/dist/cli/menu/index.js +180 -0
  64. package/dist/cli/menu/settings/categories.d.ts +9 -0
  65. package/dist/cli/menu/settings/categories.js +28 -0
  66. package/dist/cli/menu/settings/config-file.d.ts +40 -0
  67. package/dist/cli/menu/settings/config-file.js +71 -0
  68. package/dist/cli/menu/settings/editors.d.ts +30 -0
  69. package/dist/cli/menu/settings/editors.js +305 -0
  70. package/dist/cli/menu/settings/index.d.ts +32 -0
  71. package/dist/cli/menu/settings/index.js +136 -0
  72. package/dist/cli/menu/settings/schema-node.d.ts +62 -0
  73. package/dist/cli/menu/settings/schema-node.js +104 -0
  74. package/dist/cli/menu/several.d.ts +20 -0
  75. package/dist/cli/menu/several.js +102 -0
  76. package/dist/cli/progress.d.ts +9 -0
  77. package/dist/cli/progress.js +49 -0
  78. package/dist/cli/tui/app.d.ts +39 -0
  79. package/dist/cli/tui/app.js +52 -0
  80. package/dist/cli/tui/dialogs.d.ts +57 -0
  81. package/dist/cli/tui/dialogs.js +162 -0
  82. package/dist/cli/tui/frame.d.ts +18 -0
  83. package/dist/cli/tui/frame.js +27 -0
  84. package/dist/cli/tui/index.d.ts +7 -0
  85. package/dist/cli/tui/index.js +8 -0
  86. package/dist/cli/tui/list-screen.d.ts +101 -0
  87. package/dist/cli/tui/list-screen.js +299 -0
  88. package/dist/cli/tui/terminal.d.ts +37 -0
  89. package/dist/cli/tui/terminal.js +89 -0
  90. package/dist/cli/tui/text.d.ts +20 -0
  91. package/dist/cli/tui/text.js +105 -0
  92. package/dist/cli/tui/theme.d.ts +45 -0
  93. package/dist/cli/tui/theme.js +30 -0
  94. package/dist/cli/validate.d.ts +17 -0
  95. package/dist/cli/validate.js +89 -0
  96. package/dist/core/config.js +12 -6
  97. package/dist/core/disk.d.ts +16 -0
  98. package/dist/core/disk.js +55 -0
  99. package/dist/core/local-config.d.ts +23 -0
  100. package/dist/core/local-config.js +79 -7
  101. package/dist/core/project-policy.d.ts +15 -0
  102. package/dist/core/project-policy.js +35 -0
  103. package/dist/core/prompt.d.ts +4 -0
  104. package/dist/core/prompt.js +15 -0
  105. package/dist/core/safe-paths.d.ts +4 -0
  106. package/dist/core/safe-paths.js +37 -0
  107. package/dist/core/schema/apps.d.ts +40 -0
  108. package/dist/core/schema/apps.js +27 -0
  109. package/dist/core/schema/common.d.ts +17 -0
  110. package/dist/core/schema/common.js +15 -0
  111. package/dist/core/schema/config.d.ts +659 -0
  112. package/dist/core/schema/config.js +75 -0
  113. package/dist/core/schema/databases.d.ts +33 -0
  114. package/dist/core/schema/databases.js +35 -0
  115. package/dist/core/schema/harness.d.ts +12 -0
  116. package/dist/core/schema/harness.js +17 -0
  117. package/dist/core/schema/json-schema.d.ts +5 -0
  118. package/dist/core/schema/json-schema.js +25 -0
  119. package/dist/core/schema/profile.d.ts +32 -0
  120. package/dist/core/schema/profile.js +31 -0
  121. package/dist/core/schema/projects.d.ts +9 -0
  122. package/dist/core/schema/projects.js +11 -0
  123. package/dist/core/schema/sandbox.d.ts +78 -0
  124. package/dist/core/schema/sandbox.js +64 -0
  125. package/dist/core/schema/toolchains.d.ts +96 -0
  126. package/dist/core/schema/toolchains.js +88 -0
  127. package/dist/core/schema.d.ts +6 -604
  128. package/dist/core/schema.js +8 -264
  129. package/dist/core/types.d.ts +35 -1
  130. package/dist/core/util.d.ts +9 -0
  131. package/dist/core/util.js +14 -3
  132. package/dist/core/workspace.d.ts +0 -5
  133. package/dist/core/workspace.js +33 -50
  134. package/dist/guest/apps/index.d.ts +10 -0
  135. package/dist/guest/apps/index.js +206 -0
  136. package/dist/guest/apps/resolvers.d.ts +8 -0
  137. package/dist/guest/apps/resolvers.js +90 -0
  138. package/dist/guest/audit-parse.d.ts +7 -0
  139. package/dist/guest/audit-parse.js +24 -0
  140. package/dist/guest/audit.d.ts +4 -0
  141. package/dist/guest/audit.js +47 -0
  142. package/dist/guest/boot-env.d.ts +4 -0
  143. package/dist/guest/boot-env.js +25 -0
  144. package/dist/guest/cmdline.d.ts +12 -0
  145. package/dist/guest/cmdline.js +23 -0
  146. package/dist/guest/daemon/exec.d.ts +5 -0
  147. package/dist/guest/daemon/exec.js +32 -0
  148. package/dist/guest/daemon/project.d.ts +14 -0
  149. package/dist/guest/daemon/project.js +132 -0
  150. package/dist/guest/daemon/relays.d.ts +1 -0
  151. package/dist/guest/daemon/relays.js +18 -0
  152. package/dist/guest/daemon/session.d.ts +13 -0
  153. package/dist/guest/daemon/session.js +139 -0
  154. package/dist/guest/daemon/shutdown.d.ts +1 -0
  155. package/dist/guest/daemon/shutdown.js +21 -0
  156. package/dist/guest/daemon/state.d.ts +17 -0
  157. package/dist/guest/daemon/state.js +31 -0
  158. package/dist/guest/daemon.js +12 -141
  159. package/dist/guest/db.js +18 -3
  160. package/dist/guest/env.d.ts +3 -0
  161. package/dist/guest/env.js +7 -3
  162. package/dist/guest/guide.d.ts +6 -2
  163. package/dist/guest/guide.js +5 -4
  164. package/dist/guest/helpers.d.ts +3 -0
  165. package/dist/guest/helpers.js +26 -0
  166. package/dist/guest/main.js +31 -8
  167. package/dist/guest/netproxy.d.ts +1 -0
  168. package/dist/guest/netproxy.js +100 -0
  169. package/dist/guest/ports.d.ts +6 -0
  170. package/dist/guest/ports.js +22 -0
  171. package/dist/guest/project-context.d.ts +7 -0
  172. package/dist/guest/project-context.js +10 -0
  173. package/dist/guest/project-env.d.ts +20 -0
  174. package/dist/guest/project-env.js +20 -0
  175. package/dist/guest/project-status.d.ts +5 -0
  176. package/dist/guest/project-status.js +17 -0
  177. package/dist/guest/ptyhost.d.ts +0 -18
  178. package/dist/guest/ptyhost.js +17 -65
  179. package/dist/guest/setup/agents.d.ts +5 -2
  180. package/dist/guest/setup/agents.js +22 -8
  181. package/dist/guest/setup/claude.d.ts +0 -4
  182. package/dist/guest/setup/claude.js +59 -5
  183. package/dist/guest/setup/environment.d.ts +13 -3
  184. package/dist/guest/setup/environment.js +14 -10
  185. package/dist/guest/setup/hooks.d.ts +9 -1
  186. package/dist/guest/setup/hooks.js +28 -14
  187. package/dist/guest/setup/network.d.ts +9 -0
  188. package/dist/guest/setup/network.js +97 -4
  189. package/dist/guest/setup/user.js +4 -0
  190. package/dist/guest/toolchains/catalogue.d.ts +4 -0
  191. package/dist/guest/toolchains/catalogue.js +2 -2
  192. package/dist/guest/toolchains/cli.js +25 -17
  193. package/dist/guest/toolchains/common.d.ts +18 -1
  194. package/dist/guest/toolchains/common.js +34 -11
  195. package/dist/guest/toolchains/databases/dynamodb.d.ts +8 -0
  196. package/dist/guest/toolchains/databases/dynamodb.js +52 -0
  197. package/dist/guest/toolchains/{databases.d.ts → databases/index.d.ts} +2 -3
  198. package/dist/guest/toolchains/databases/index.js +62 -0
  199. package/dist/guest/toolchains/databases/mongodb.d.ts +3 -0
  200. package/dist/guest/toolchains/databases/mongodb.js +31 -0
  201. package/dist/guest/toolchains/databases/mysql.d.ts +3 -0
  202. package/dist/guest/toolchains/databases/mysql.js +38 -0
  203. package/dist/guest/toolchains/databases/postgres.d.ts +5 -0
  204. package/dist/guest/toolchains/databases/postgres.js +38 -0
  205. package/dist/guest/toolchains/databases/redis.d.ts +3 -0
  206. package/dist/guest/toolchains/databases/redis.js +16 -0
  207. package/dist/guest/toolchains/databases/server.d.ts +14 -0
  208. package/dist/guest/toolchains/databases/server.js +52 -0
  209. package/dist/guest/toolchains/git.js +25 -16
  210. package/dist/guest/toolchains/go.js +1 -1
  211. package/dist/guest/toolchains/index.d.ts +13 -9
  212. package/dist/guest/toolchains/index.js +40 -82
  213. package/dist/guest/toolchains/java.js +5 -5
  214. package/dist/guest/toolchains/leftovers.d.ts +2 -0
  215. package/dist/guest/toolchains/leftovers.js +26 -0
  216. package/dist/guest/toolchains/managers.js +12 -10
  217. package/dist/guest/toolchains/{binstall.js → native/binstall.js} +6 -9
  218. package/dist/guest/toolchains/native/cpp.d.ts +4 -0
  219. package/dist/guest/toolchains/native/cpp.js +38 -0
  220. package/dist/guest/toolchains/native/dotnet.d.ts +4 -0
  221. package/dist/guest/toolchains/native/dotnet.js +103 -0
  222. package/dist/guest/toolchains/native/mesa.d.ts +7 -0
  223. package/dist/guest/toolchains/native/mesa.js +56 -0
  224. package/dist/guest/toolchains/native/msvc/environment.d.ts +16 -0
  225. package/dist/guest/toolchains/native/msvc/environment.js +57 -0
  226. package/dist/guest/toolchains/native/msvc/index.d.ts +6 -0
  227. package/dist/guest/toolchains/native/msvc/index.js +48 -0
  228. package/dist/guest/toolchains/native/msvc/packages.d.ts +6 -0
  229. package/dist/guest/toolchains/native/msvc/packages.js +156 -0
  230. package/dist/guest/toolchains/native/msvc/tree.d.ts +15 -0
  231. package/dist/guest/toolchains/native/msvc/tree.js +21 -0
  232. package/dist/guest/toolchains/native/rust.d.ts +3 -0
  233. package/dist/guest/toolchains/native/rust.js +45 -0
  234. package/dist/guest/toolchains/node.js +26 -6
  235. package/dist/guest/toolchains/plan.d.ts +24 -0
  236. package/dist/guest/toolchains/plan.js +140 -0
  237. package/dist/guest/toolchains/pwsh.js +1 -1
  238. package/dist/guest/toolchains/python.js +43 -12
  239. package/dist/guest/toolchains/runtimes.d.ts +2 -0
  240. package/dist/guest/toolchains/runtimes.js +6 -8
  241. package/dist/guest/toolchains/scripting/php.d.ts +3 -0
  242. package/dist/guest/toolchains/scripting/php.js +71 -0
  243. package/dist/guest/toolchains/scripting/ruby.d.ts +3 -0
  244. package/dist/guest/toolchains/scripting/ruby.js +47 -0
  245. package/dist/guest/toolchains/scripting/vcruntime.d.ts +7 -0
  246. package/dist/guest/toolchains/scripting/vcruntime.js +45 -0
  247. package/dist/guest/toolchains/vscode-profile.d.ts +30 -0
  248. package/dist/guest/toolchains/vscode-profile.js +69 -0
  249. package/dist/guest/toolchains/vscode.d.ts +17 -0
  250. package/dist/guest/toolchains/vscode.js +87 -1
  251. package/dist/guest/view.js +21 -1
  252. package/dist/host/accounts.js +14 -5
  253. package/dist/host/agent-commands.d.ts +25 -0
  254. package/dist/host/agent-commands.js +145 -0
  255. package/dist/host/attach.d.ts +17 -0
  256. package/dist/host/attach.js +70 -0
  257. package/dist/host/audit/collect.d.ts +34 -0
  258. package/dist/host/audit/collect.js +126 -0
  259. package/dist/host/audit/log.d.ts +46 -0
  260. package/dist/host/audit/log.js +143 -0
  261. package/dist/host/channel.d.ts +23 -22
  262. package/dist/host/channel.js +66 -84
  263. package/dist/host/claude-profile.js +7 -3
  264. package/dist/host/cleanup.js +2 -11
  265. package/dist/host/database-plan.d.ts +12 -0
  266. package/dist/host/database-plan.js +52 -0
  267. package/dist/host/generate.d.ts +10 -12
  268. package/dist/host/generate.js +58 -135
  269. package/dist/host/join.d.ts +28 -0
  270. package/dist/host/join.js +76 -0
  271. package/dist/host/launch/mappings.d.ts +3 -0
  272. package/dist/host/launch/mappings.js +54 -0
  273. package/dist/host/launch/projects.d.ts +15 -0
  274. package/dist/host/launch/projects.js +56 -0
  275. package/dist/host/launch/stage.d.ts +11 -0
  276. package/dist/host/launch/stage.js +66 -0
  277. package/dist/host/launch/wsb.d.ts +10 -0
  278. package/dist/host/launch/wsb.js +34 -0
  279. package/dist/host/motw.d.ts +17 -0
  280. package/dist/host/motw.js +74 -0
  281. package/dist/host/pc-scan.d.ts +6 -0
  282. package/dist/host/pc-scan.js +37 -0
  283. package/dist/host/platform.d.ts +2 -0
  284. package/dist/host/platform.js +16 -1
  285. package/dist/host/port-forward.d.ts +8 -0
  286. package/dist/host/port-forward.js +37 -0
  287. package/dist/host/project-scan.d.ts +1 -17
  288. package/dist/host/project-scan.js +2 -86
  289. package/dist/host/projects.d.ts +100 -0
  290. package/dist/host/projects.js +147 -0
  291. package/dist/host/repo-guard.d.ts +25 -5
  292. package/dist/host/repo-guard.js +242 -23
  293. package/dist/host/stops.d.ts +67 -0
  294. package/dist/host/stops.js +126 -0
  295. package/dist/host/terminal.d.ts +8 -0
  296. package/dist/host/terminal.js +48 -1
  297. package/dist/host/test-guard.d.ts +6 -0
  298. package/dist/host/test-guard.js +15 -0
  299. package/dist/host/window.js +7 -3
  300. package/dist/host/workspace-view/index.d.ts +20 -0
  301. package/dist/host/workspace-view/index.js +53 -0
  302. package/dist/host/workspace-view/rules.d.ts +26 -0
  303. package/dist/host/workspace-view/rules.js +93 -0
  304. package/dist/host/workspace-view/view.d.ts +50 -0
  305. package/dist/host/workspace-view/view.js +281 -0
  306. package/dist/host/wsb.d.ts +37 -0
  307. package/dist/host/wsb.js +101 -0
  308. package/dist/runtime/daemon.js +11791 -2821
  309. package/dist/runtime/db.js +6585 -466
  310. package/dist/runtime/main.js +10238 -1724
  311. package/dist/runtime/netproxy.js +25936 -0
  312. package/dist/runtime/view.js +6183 -59
  313. package/dist/selftest/accounts.test.d.ts +2 -0
  314. package/dist/selftest/accounts.test.js +44 -0
  315. package/dist/selftest/agent-commands.test.d.ts +2 -0
  316. package/dist/selftest/agent-commands.test.js +47 -0
  317. package/dist/selftest/audit.test.d.ts +2 -0
  318. package/dist/selftest/audit.test.js +57 -0
  319. package/dist/selftest/channel.test.d.ts +2 -0
  320. package/dist/selftest/channel.test.js +44 -0
  321. package/dist/selftest/cli.test.d.ts +2 -2
  322. package/dist/selftest/cli.test.js +145 -27
  323. package/dist/selftest/cmdline.test.d.ts +2 -0
  324. package/dist/selftest/cmdline.test.js +45 -0
  325. package/dist/selftest/config.test.d.ts +2 -3
  326. package/dist/selftest/config.test.js +36 -72
  327. package/dist/selftest/data.test.d.ts +2 -2
  328. package/dist/selftest/data.test.js +77 -70
  329. package/dist/selftest/detect.test.d.ts +2 -2
  330. package/dist/selftest/detect.test.js +54 -38
  331. package/dist/selftest/fixtures.d.ts +89 -4
  332. package/dist/selftest/fixtures.js +43 -24
  333. package/dist/selftest/generate.test.d.ts +2 -0
  334. package/dist/selftest/generate.test.js +68 -0
  335. package/dist/selftest/git-access.test.d.ts +2 -0
  336. package/dist/selftest/git-access.test.js +26 -0
  337. package/dist/selftest/guest-boot.test.d.ts +2 -0
  338. package/dist/selftest/guest-boot.test.js +76 -0
  339. package/dist/selftest/harness.d.ts +44 -7
  340. package/dist/selftest/harness.js +62 -21
  341. package/dist/selftest/host-sim.test.d.ts +2 -0
  342. package/dist/selftest/host-sim.test.js +93 -0
  343. package/dist/selftest/hostile-input.test.d.ts +2 -0
  344. package/dist/selftest/hostile-input.test.js +54 -0
  345. package/dist/selftest/index.d.ts +8 -1
  346. package/dist/selftest/index.js +137 -35
  347. package/dist/selftest/links.test.d.ts +2 -0
  348. package/dist/selftest/links.test.js +50 -0
  349. package/dist/selftest/live-daemon.test.d.ts +2 -0
  350. package/dist/selftest/live-daemon.test.js +91 -0
  351. package/dist/selftest/live-git.test.d.ts +2 -0
  352. package/dist/selftest/live-git.test.js +60 -0
  353. package/dist/selftest/live-network.test.d.ts +2 -0
  354. package/dist/selftest/live-network.test.js +63 -0
  355. package/dist/selftest/live-projects.test.d.ts +2 -0
  356. package/dist/selftest/live-projects.test.js +127 -0
  357. package/dist/selftest/live.d.ts +65 -0
  358. package/dist/selftest/live.js +109 -0
  359. package/dist/selftest/local-config.test.d.ts +2 -0
  360. package/dist/selftest/local-config.test.js +120 -0
  361. package/dist/selftest/mirror.test.d.ts +2 -3
  362. package/dist/selftest/mirror.test.js +92 -65
  363. package/dist/selftest/network.test.d.ts +2 -0
  364. package/dist/selftest/network.test.js +40 -0
  365. package/dist/selftest/personalization.test.d.ts +2 -0
  366. package/dist/selftest/personalization.test.js +53 -0
  367. package/dist/selftest/projects.test.d.ts +2 -0
  368. package/dist/selftest/projects.test.js +254 -0
  369. package/dist/selftest/repair.test.d.ts +2 -0
  370. package/dist/selftest/repair.test.js +42 -0
  371. package/dist/selftest/repo-guard.test.d.ts +2 -0
  372. package/dist/selftest/repo-guard.test.js +121 -0
  373. package/dist/selftest/secrets.test.d.ts +2 -0
  374. package/dist/selftest/secrets.test.js +71 -0
  375. package/dist/selftest/setup.test.d.ts +2 -2
  376. package/dist/selftest/setup.test.js +45 -22
  377. package/dist/selftest/suite.d.ts +13 -0
  378. package/dist/selftest/suite.js +1 -0
  379. package/dist/selftest/sync.test.d.ts +2 -3
  380. package/dist/selftest/sync.test.js +130 -78
  381. package/dist/selftest/test-guard.test.d.ts +2 -0
  382. package/dist/selftest/test-guard.test.js +49 -0
  383. package/dist/selftest/toolchains.test.d.ts +2 -0
  384. package/dist/selftest/toolchains.test.js +133 -0
  385. package/dist/selftest/workspace-view.test.d.ts +2 -0
  386. package/dist/selftest/workspace-view.test.js +89 -0
  387. package/dist/selftest/workspace.test.d.ts +2 -0
  388. package/dist/selftest/workspace.test.js +53 -0
  389. package/dist/shared/apps.d.ts +49 -0
  390. package/dist/shared/apps.js +114 -0
  391. package/dist/shared/download.d.ts +3 -1
  392. package/dist/shared/download.js +19 -4
  393. package/dist/shared/netpolicy.d.ts +27 -0
  394. package/dist/shared/netpolicy.js +51 -0
  395. package/dist/shared/paths.d.ts +5 -0
  396. package/dist/shared/paths.js +6 -0
  397. package/dist/shared/projects.d.ts +53 -0
  398. package/dist/shared/projects.js +67 -0
  399. package/dist/shared/pty-client.d.ts +9 -4
  400. package/dist/shared/pty-client.js +139 -17
  401. package/dist/shared/rundir.d.ts +12 -1
  402. package/dist/shared/rundir.js +14 -4
  403. package/dist/shared/safe-remove.js +11 -0
  404. package/dist/shared/schema.d.ts +453 -0
  405. package/dist/shared/schema.js +43 -2
  406. package/dist/shared/system.d.ts +1 -0
  407. package/dist/shared/system.js +1 -0
  408. package/dist/shared/test-guard.d.ts +4 -0
  409. package/dist/shared/test-guard.js +37 -0
  410. package/dist/sync/claude-mem.js +6 -3
  411. package/dist/sync/history.d.ts +29 -12
  412. package/dist/sync/history.js +72 -25
  413. package/dist/sync/watcher.d.ts +8 -0
  414. package/dist/sync/watcher.js +99 -8
  415. package/package.json +7 -6
  416. package/sandbox/bootstrap.ps1 +258 -258
  417. package/sandbox/cargoshim.cs +56 -0
  418. package/sandbox/cpucap.cs +33 -0
  419. package/sandbox/cpucap.ps1 +20 -0
  420. package/sandbox/logon.cmd +24 -16
  421. package/sandbox/memlog.ps1 +34 -0
  422. package/sandbox/openssl.cs +42 -0
  423. package/sandbox/pagefile.cs +31 -0
  424. package/sandbox/pagefile.ps1 +21 -0
  425. package/sandbox/ptyhost.cs +120 -11
  426. package/sandbox/trust.cmd +35 -35
  427. package/schemas/config.schema.json +403 -3
  428. package/schemas/sandbox-config.schema.json +143 -13
  429. package/dist/cli/commands/data.d.ts +0 -46
  430. package/dist/cli/commands/data.js +0 -249
  431. package/dist/cli/commands/setup.js +0 -152
  432. package/dist/cli/menu.d.ts +0 -22
  433. package/dist/cli/menu.js +0 -187
  434. package/dist/cli/settings.d.ts +0 -11
  435. package/dist/cli/settings.js +0 -156
  436. package/dist/guest/toolchains/databases.js +0 -226
  437. package/dist/guest/toolchains/msvc.d.ts +0 -10
  438. package/dist/guest/toolchains/msvc.js +0 -216
  439. package/dist/guest/toolchains/native.d.ts +0 -12
  440. package/dist/guest/toolchains/native.js +0 -220
  441. package/dist/guest/toolchains/scripting.d.ts +0 -10
  442. package/dist/guest/toolchains/scripting.js +0 -137
  443. package/dist/selftest/guest.test.d.ts +0 -3
  444. package/dist/selftest/guest.test.js +0 -61
  445. package/dist/selftest/helpers.test.d.ts +0 -2
  446. package/dist/selftest/helpers.test.js +0 -125
  447. package/dist/selftest/host.test.d.ts +0 -2
  448. package/dist/selftest/host.test.js +0 -71
  449. package/dist/selftest/live.test.d.ts +0 -7
  450. package/dist/selftest/live.test.js +0 -127
  451. package/dist/selftest/security.test.d.ts +0 -3
  452. package/dist/selftest/security.test.js +0 -143
  453. /package/dist/guest/toolchains/{binstall.d.ts → native/binstall.d.ts} +0 -0
@@ -32,6 +32,24 @@
32
32
  "type": "boolean",
33
33
  "description": "Map this project read-only."
34
34
  },
35
+ "workspaceFilter": {
36
+ "type": "object",
37
+ "properties": {
38
+ "enabled": {
39
+ "type": "boolean",
40
+ "description": "Keep what your .gitignore lists (.env files, node_modules, build output ...) out of the sandbox. The sandbox works on a copy of the project without those files, kept in step with it both ways within about a second; what it creates that is ignored (its own node_modules, builds) stays in the sandbox. Git works as usual. Off = the project folder itself is mapped."
41
+ },
42
+ "exclude": {
43
+ "type": "array",
44
+ "items": {
45
+ "type": "string",
46
+ "maxLength": 500
47
+ },
48
+ "description": "Also keep these out, as .gitignore patterns, e.g. secrets/, *.pem, data/private/."
49
+ }
50
+ },
51
+ "additionalProperties": false
52
+ },
35
53
  "mappings": {
36
54
  "type": "array",
37
55
  "items": {
@@ -62,7 +80,7 @@
62
80
  ],
63
81
  "additionalProperties": false
64
82
  },
65
- "description": "Extra folders (relative to this file)."
83
+ "description": "Extra folders inside this project (relative to this file), e.g. a read-only data folder at another place in the sandbox."
66
84
  },
67
85
  "scripts": {
68
86
  "type": "array",
@@ -94,6 +112,12 @@
94
112
  "maximum": 9007199254740991,
95
113
  "description": "Upper limit for memoryMb \"auto\"."
96
114
  },
115
+ "maxMemoryPercent": {
116
+ "type": "integer",
117
+ "minimum": 10,
118
+ "maximum": 100,
119
+ "description": "memoryMb \"auto\" never takes more than this share of this PC's total RAM (percent)."
120
+ },
97
121
  "reserveHostMb": {
98
122
  "type": "integer",
99
123
  "minimum": 0,
@@ -131,6 +155,10 @@
131
155
  "headless": {
132
156
  "type": "boolean",
133
157
  "description": "Hide the sandbox window (sbx-show brings it back). A headless sandbox shuts down when its last session ends."
158
+ },
159
+ "keepAwake": {
160
+ "type": "boolean",
161
+ "description": "Keep this PC from sleeping while a sandbox runs, so agents left working overnight keep going (the screen may still turn off; closing a laptop lid still sleeps it)."
134
162
  }
135
163
  },
136
164
  "additionalProperties": false
@@ -139,7 +167,17 @@
139
167
  "type": "object",
140
168
  "properties": {
141
169
  "blockPrivateRanges": {
142
- "type": "boolean"
170
+ "type": "boolean",
171
+ "description": "Block your LAN (10/8, 172.16/12, 192.168/16, SMB) from inside the sandbox."
172
+ },
173
+ "blockHosts": {
174
+ "type": "array",
175
+ "items": {
176
+ "type": "string",
177
+ "maxLength": 253,
178
+ "pattern": "^([a-zA-Z0-9-]+\\.)*[a-zA-Z0-9-]+$"
179
+ },
180
+ "description": "Never reachable from the sandbox, e.g. production servers or telemetry (each exact name; the sandbox's hosts file sends them nowhere)."
143
181
  }
144
182
  },
145
183
  "additionalProperties": false
@@ -191,6 +229,16 @@
191
229
  },
192
230
  "additionalProperties": false
193
231
  },
232
+ "downloads": {
233
+ "type": "object",
234
+ "properties": {
235
+ "requireChecksum": {
236
+ "type": "boolean",
237
+ "description": "Refuse any toolchain, database or tool download that has no published checksum (SHA-256/SHA-512) to verify it against. false = allow those, as before. Downloads that do have a published checksum are always verified. A project's .sandbox-config.json can only turn this on."
238
+ }
239
+ },
240
+ "additionalProperties": false
241
+ },
194
242
  "toolchains": {
195
243
  "type": "object",
196
244
  "properties": {
@@ -685,6 +733,22 @@
685
733
  "enabled": {
686
734
  "type": "boolean",
687
735
  "description": "Portable VS Code inside the sandbox (code on PATH, desktop shortcut); its settings and extensions persist."
736
+ },
737
+ "setup": {
738
+ "type": "boolean",
739
+ "description": "Point VS Code at the sandbox's own tools (JDK, Python, Go, compilers, .NET, Git, PowerShell 7 and Git Bash terminals) and install the language extensions for the toolchains in use."
740
+ },
741
+ "recommended": {
742
+ "type": "boolean",
743
+ "description": "Also install the extensions a project recommends in its .vscode/extensions.json."
744
+ },
745
+ "extensions": {
746
+ "type": "array",
747
+ "items": {
748
+ "type": "string",
749
+ "pattern": "^[\\w-]+\\.[\\w-]+$"
750
+ },
751
+ "description": "More extensions to install in every sandbox, e.g. eamodio.gitlens, ms-azuretools.vscode-docker."
688
752
  }
689
753
  },
690
754
  "additionalProperties": false
@@ -864,7 +928,7 @@
864
928
  "const": "auto"
865
929
  }
866
930
  ],
867
- "description": "SQL Server. It cannot run inside Windows Sandbox; when a project needs it you get a hint to reach the one on this PC through hostAccess.forwards: true, false, or \"auto\" = only when the project needs it (found from compose files, dependencies of every language, Prisma/ORM config and connection strings)."
931
+ "description": "SQL Server. It cannot run inside Windows Sandbox; when a project needs it you get a note to use Postgres or SQLite for local work: true, false, or \"auto\" = only when the project needs it (found from compose files, dependencies of every language, Prisma/ORM config and connection strings)."
868
932
  }
869
933
  },
870
934
  "additionalProperties": false
@@ -904,20 +968,86 @@
904
968
  },
905
969
  "additionalProperties": false
906
970
  },
907
- "claudeProfile": {
971
+ "apps": {
908
972
  "type": "object",
909
973
  "properties": {
910
- "enabled": {
911
- "type": "boolean",
912
- "description": "Copy selected Claude settings from this PC into the sandbox."
913
- },
914
- "include": {
974
+ "install": {
915
975
  "type": "array",
916
976
  "items": {
917
977
  "type": "string",
918
- "pattern": "^[A-Za-z0-9._-]+$"
978
+ "enum": [
979
+ "notepadpp",
980
+ "sublime",
981
+ "neovim",
982
+ "dbeaver",
983
+ "pgadmin",
984
+ "heidisql",
985
+ "sqlitebrowser",
986
+ "compass",
987
+ "redisinsight",
988
+ "dbgate",
989
+ "beekeeper",
990
+ "dynamodb-admin",
991
+ "bruno",
992
+ "insomnia",
993
+ "sourcegit",
994
+ "githubdesktop",
995
+ "lazygit",
996
+ "7zip",
997
+ "winmerge",
998
+ "everything",
999
+ "sysinternals",
1000
+ "imhex",
1001
+ "chrome",
1002
+ "firefox",
1003
+ "godot",
1004
+ "blender",
1005
+ "love",
1006
+ "defold",
1007
+ "pixelorama",
1008
+ "tiled",
1009
+ "kubectl",
1010
+ "helm",
1011
+ "k9s",
1012
+ "terraform",
1013
+ "azure-cli",
1014
+ "gcloud",
1015
+ "aws-cli",
1016
+ "drawio",
1017
+ "pandoc",
1018
+ "mitmproxy",
1019
+ "xh",
1020
+ "grpcurl",
1021
+ "k6",
1022
+ "jq",
1023
+ "yq",
1024
+ "ripgrep",
1025
+ "fd",
1026
+ "bat",
1027
+ "fzf",
1028
+ "delta",
1029
+ "just",
1030
+ "hyperfine",
1031
+ "watchexec",
1032
+ "protoc",
1033
+ "ninja",
1034
+ "ffmpeg",
1035
+ "sqlite",
1036
+ "shellcheck",
1037
+ "gitleaks"
1038
+ ]
919
1039
  },
920
- "description": "Files and folders copied from it."
1040
+ "description": "Apps from the catalogue to install in every sandbox (the Apps screen in the menu lists them by category). Each is downloaded once and kept."
1041
+ }
1042
+ },
1043
+ "additionalProperties": false
1044
+ },
1045
+ "claudeProfile": {
1046
+ "type": "object",
1047
+ "properties": {
1048
+ "enabled": {
1049
+ "type": "boolean",
1050
+ "description": "Copy selected Claude settings from this PC into the sandbox."
921
1051
  },
922
1052
  "overwrite": {
923
1053
  "type": "boolean",
@@ -929,11 +1059,11 @@
929
1059
  },
930
1060
  "syncHistory": {
931
1061
  "type": "boolean",
932
- "description": "Bring all conversation history in, and sync new history back (path-translated)."
1062
+ "description": "Bring conversation history in, and sync new history back (path-translated)."
933
1063
  },
934
1064
  "syncClaudeMem": {
935
1065
  "type": "boolean",
936
- "description": "Bring claude-mem data in, and its database back when the sandbox closes."
1066
+ "description": "Bring claude-mem data into the sandbox (its settings and backups stay on this PC)."
937
1067
  }
938
1068
  },
939
1069
  "additionalProperties": false
@@ -1,46 +0,0 @@
1
- import { type Context } from './context.js';
2
- export type DataArea = 'tools' | 'databases' | 'state' | 'logs' | 'data' | 'host';
3
- export interface DataEntry {
4
- area: DataArea;
5
- name: string;
6
- path: string;
7
- bytes: number;
8
- }
9
- /** 1536 -> "1.5 KB". */
10
- export declare const humanBytes: (bytes: number) => string;
11
- /** Size on disk, never following links or junctions (a link counts as 0). */
12
- export declare const sizeOf: (p: string) => number;
13
- /**
14
- * Deletes a folder or file without ever following a link: links found anywhere inside are removed themselves first,
15
- * then the (now link-free) tree is deleted. A link in place of `p` is removed itself.
16
- */
17
- /** Deletes p (strictly inside root): links inside are removed first and never followed; see shared/safe-remove.ts. */
18
- export declare const removeTree: (p: string, root: string) => void;
19
- /** Every row of `sandbox data`: the sandbox's data folder by area, then what this PC keeps for it. */
20
- export declare const collectDataEntries: (dataPath: string, storageRoot: string) => DataEntry[];
21
- export interface DiskUsage {
22
- drive: string;
23
- totalBytes: number;
24
- freeBytes: number;
25
- usedBytes: number;
26
- holdsStorage: boolean;
27
- }
28
- /** Every local drive's size and free space, and which one holds the sandbox storage. */
29
- export declare const diskUsage: (storageRoot: string) => DiskUsage[];
30
- export declare const dataInfo: (ctx: Context) => number;
31
- export interface CleanTarget {
32
- /** The target as normalised (forward slashes), e.g. "tools/go". */
33
- target: string;
34
- path: string;
35
- /** Folder the target must stay inside, with no links between the two. */
36
- root: string;
37
- warning?: string;
38
- }
39
- /**
40
- * Turns `sandbox data clean` arguments into folders. Pure (no disk access); throws a UserError for anything that is
41
- * not a plain relative target inside the data folder: absolute paths, drive letters, `..`, wildcards, unknown areas.
42
- */
43
- export declare const resolveCleanTargets: (inputs: string[], dataPath: string, storageRoot: string) => CleanTarget[];
44
- export declare const dataClean: (ctx: Context) => Promise<number>;
45
- /** `sandbox data [info|clean] [targets...]`. */
46
- export declare const data: (ctx: Context) => number | Promise<number>;
@@ -1,249 +0,0 @@
1
- // `sandbox data`: what persists between sandboxes (toolchains, databases, agent state, logs, host storage) and
2
- // removing chosen parts of it. Everything under the data folder is sandbox-writable: sizes and deletes never follow
3
- // links, and targets resolve strictly inside the data folder.
4
- import fs from 'node:fs';
5
- import path from 'node:path';
6
- import readline from 'node:readline';
7
- import _ from 'lodash';
8
- import { removeRefusal, safeRemove } from '../../shared/safe-remove.js';
9
- import { assertNoLinks, dirExists, fail, isInsideOrEqual, isLink, removeLink } from '../../core/util.js';
10
- import { askYesNo } from '../../core/workspace.js';
11
- import { isSandboxRunning } from '../../host/platform.js';
12
- import { printJson, table } from './context.js';
13
- const AREA_ORDER = ['tools', 'databases', 'state', 'logs', 'data', 'host'];
14
- /** Folders of the data folder that get one row per child; anything else at the top level is listed as itself. */
15
- const PER_CHILD = ['tools', 'databases', 'state'];
16
- /** 1536 -> "1.5 KB". */
17
- export const humanBytes = (bytes) => {
18
- const units = ['B', 'KB', 'MB', 'GB', 'TB'];
19
- const i = bytes <= 0 ? 0 : Math.min(units.length - 1, Math.floor(Math.log(bytes) / Math.log(1024)));
20
- const value = bytes / 1024 ** i;
21
- return (i === 0 ? String(bytes) : value.toFixed(value < 10 ? 1 : 0)) + ' ' + units[i];
22
- };
23
- /** Size on disk, never following links or junctions (a link counts as 0). */
24
- export const sizeOf = (p) => {
25
- try {
26
- const stat = fs.lstatSync(p);
27
- if (stat.isSymbolicLink())
28
- return 0;
29
- if (!stat.isDirectory())
30
- return stat.size;
31
- return _.sumBy(fs.readdirSync(p, { withFileTypes: true }), (d) => (d.isSymbolicLink() ? 0 : sizeOf(path.join(p, d.name))));
32
- }
33
- catch {
34
- return 0;
35
- }
36
- };
37
- /**
38
- * Deletes a folder or file without ever following a link: links found anywhere inside are removed themselves first,
39
- * then the (now link-free) tree is deleted. A link in place of `p` is removed itself.
40
- */
41
- /** Deletes p (strictly inside root): links inside are removed first and never followed; see shared/safe-remove.ts. */
42
- export const removeTree = (p, root) => {
43
- const unlinkInside = (dir) => {
44
- for (const d of fs.readdirSync(dir, { withFileTypes: true })) {
45
- const child = path.join(dir, d.name);
46
- if (d.isSymbolicLink() || isLink(child))
47
- removeLink(child);
48
- else if (d.isDirectory())
49
- unlinkInside(child);
50
- }
51
- };
52
- if (isLink(p)) {
53
- removeLink(p);
54
- return;
55
- }
56
- if (!fs.existsSync(p))
57
- return;
58
- // Refused before anything is touched (safeRemove below checks again).
59
- const refusal = removeRefusal(p, root);
60
- if (refusal)
61
- throw new Error('Refusing to delete ' + p + ': ' + refusal);
62
- if (dirExists(p))
63
- unlinkInside(p);
64
- safeRemove(p, root);
65
- };
66
- /** Real (non-link) children of a real folder; a link in place of the folder yields nothing. */
67
- const entriesOf = (dir) => (dirExists(dir) && !isLink(dir) ? fs.readdirSync(dir, { withFileTypes: true }).filter((d) => !d.isSymbolicLink()) : []);
68
- const toolRows = (toolsDir) => {
69
- const entries = entriesOf(toolsDir);
70
- const folders = entries.filter((d) => d.isDirectory());
71
- const files = entries.filter((d) => !d.isDirectory());
72
- const row = (name, p) => ({ area: 'tools', name, path: p, bytes: sizeOf(p) });
73
- return [
74
- ...folders.flatMap((d) => (d.name.toLowerCase() === 'agents'
75
- ? entriesOf(path.join(toolsDir, d.name)).map((a) => row('agents/' + a.name, path.join(toolsDir, d.name, a.name)))
76
- : [row(d.name, path.join(toolsDir, d.name))])),
77
- ...(files.length ? [{ area: 'tools', name: '(files in tools)', path: toolsDir, bytes: _.sumBy(files, (f) => sizeOf(path.join(toolsDir, f.name))) }] : []),
78
- ];
79
- };
80
- /** Every row of `sandbox data`: the sandbox's data folder by area, then what this PC keeps for it. */
81
- export const collectDataEntries = (dataPath, storageRoot) => {
82
- const inData = entriesOf(dataPath);
83
- const rows = inData.flatMap((d) => {
84
- const p = path.join(dataPath, d.name);
85
- const area = d.name.toLowerCase();
86
- if (area === 'tools')
87
- return toolRows(p);
88
- if (PER_CHILD.includes(area))
89
- return entriesOf(p).map((c) => ({ area, name: area + '/' + c.name, path: path.join(p, c.name), bytes: sizeOf(path.join(p, c.name)) }));
90
- return [{ area: area === 'logs' ? 'logs' : 'data', name: d.name, path: p, bytes: sizeOf(p) }];
91
- });
92
- const otherData = entriesOf(path.join(storageRoot, 'data')).filter((d) => d.isDirectory() && path.join(storageRoot, 'data', d.name).toLowerCase() !== path.resolve(dataPath).toLowerCase());
93
- const host = [
94
- ...['launches', 'accounts', 'sync', 'logs', 'run', 'host'].map((name) => ({ area: 'host', name, path: path.join(storageRoot, name), bytes: sizeOf(path.join(storageRoot, name)) })),
95
- ...otherData.map((d) => ({ area: 'host', name: 'other data folder: ' + d.name, path: path.join(storageRoot, 'data', d.name), bytes: sizeOf(path.join(storageRoot, 'data', d.name)) })),
96
- ].filter((r) => fs.existsSync(r.path));
97
- return _.sortBy([...rows, ...host], (r) => AREA_ORDER.indexOf(r.area), (r) => -r.bytes, (r) => r.name.toLowerCase());
98
- };
99
- const AREA_LABEL = { tools: 'Toolchains', databases: 'Databases', state: 'Agent state', logs: 'Logs', data: 'Other', host: 'On this PC' };
100
- /** Every local drive's size and free space, and which one holds the sandbox storage. */
101
- export const diskUsage = (storageRoot) => {
102
- const storageDrive = path.parse(path.resolve(storageRoot)).root.toUpperCase();
103
- return 'CDEFGHIJKLMNOPQRSTUVWXYZ'.split('').map((letter) => letter + ':\\').flatMap((drive) => {
104
- try {
105
- const s = fs.statfsSync(drive);
106
- const totalBytes = s.blocks * s.bsize;
107
- if (!totalBytes)
108
- return [];
109
- return [{ drive, totalBytes, freeBytes: s.bavail * s.bsize, usedBytes: totalBytes - s.bfree * s.bsize, holdsStorage: drive.toUpperCase() === storageDrive }];
110
- }
111
- catch {
112
- return [];
113
- }
114
- });
115
- };
116
- export const dataInfo = (ctx) => {
117
- const entries = collectDataEntries(ctx.dataPath, ctx.storageRoot);
118
- const total = _.sumBy(entries, 'bytes');
119
- const disks = diskUsage(ctx.storageRoot);
120
- if (printJson(ctx, { dataPath: ctx.dataPath, storageRoot: ctx.storageRoot, totalBytes: total, entries, disks }))
121
- return 0;
122
- console.log('Disks\n');
123
- table([['DRIVE', 'USED', 'FREE', 'SIZE', ''], ...disks.map((d) => [d.drive, humanBytes(d.usedBytes) + ' (' + Math.round((d.usedBytes / d.totalBytes) * 100) + '%)', humanBytes(d.freeBytes), humanBytes(d.totalBytes), d.holdsStorage ? '<- sandbox storage (' + humanBytes(total) + ' of it)' : ''])]);
124
- console.log('');
125
- console.log('Persistent data for the sandbox: ' + ctx.dataPath + ' (C:\\AgentData inside)\n');
126
- if (!entries.length) {
127
- console.log('Nothing stored yet. Toolchains, databases and agent logins appear here after the first start.');
128
- return 0;
129
- }
130
- const rows = _.flatMap(_.groupBy(entries, 'area'), (group, area) => [
131
- [AREA_LABEL[area], humanBytes(_.sumBy(group, 'bytes')), ''],
132
- ...group.map((e) => [' ' + e.name, humanBytes(e.bytes), e.path]),
133
- ]);
134
- table([...rows, ['', '', ''], ['Total', humanBytes(total), '']]);
135
- console.log('\nFree space with: sandbox data clean <target...> (e.g. tools/go, databases/postgres-18, logs, launches)');
136
- return 0;
137
- };
138
- const DATA_AREAS = ['tools', 'databases', 'state', 'logs'];
139
- const SEGMENT = /^[A-Za-z0-9][A-Za-z0-9._ +@-]*$/;
140
- const LOGIN_WARNING = 'removes the agent logins, settings and history inside the sandbox (save a Claude login first with: sandbox account save <name>)';
141
- const ALL_WARNING = 'removes EVERYTHING the sandbox keeps: toolchains, databases, agent logins and history, logs and launch folders';
142
- /**
143
- * Turns `sandbox data clean` arguments into folders. Pure (no disk access); throws a UserError for anything that is
144
- * not a plain relative target inside the data folder: absolute paths, drive letters, `..`, wildcards, unknown areas.
145
- */
146
- export const resolveCleanTargets = (inputs, dataPath, storageRoot) => {
147
- const usage = 'Targets: all | tools | tools/<name> | tools/agents/<name> | databases | databases/<name> | state | state/<agent> | logs | launches. See them with: sandbox data';
148
- if (!inputs.length)
149
- fail('Say what to remove.', usage);
150
- const resolved = inputs.map((raw) => {
151
- const input = raw.trim();
152
- if (!input)
153
- fail('Empty target.', usage);
154
- if (path.win32.isAbsolute(input) || path.posix.isAbsolute(input) || /^[A-Za-z]:/.test(input) || input.includes(':'))
155
- fail('Refusing "' + raw + '": targets are relative to the data folder, not paths on this PC.', usage);
156
- const parts = input.replace(/\\/g, '/').split('/').filter(Boolean);
157
- const bad = parts.find((p) => !SEGMENT.test(p) || /^\.+$/.test(p) || /[. ]$/.test(p));
158
- if (bad !== undefined)
159
- fail('Refusing "' + raw + '": "' + bad + '" is not a plain folder name (no .., wildcards or special characters).', usage);
160
- const [head, ...rest] = parts;
161
- const area = head.toLowerCase();
162
- if (parts.length > 3)
163
- fail('Refusing "' + raw + '": too deep.', usage);
164
- const target = [area, ...rest].join('/');
165
- if (area === 'all' && !rest.length)
166
- return { target: 'all', path: dataPath, root: path.join(storageRoot, 'data'), warning: ALL_WARNING };
167
- if (area === 'launches')
168
- return { target, path: path.join(storageRoot, 'launches', ...rest), root: storageRoot };
169
- if (area === 'accounts' || area === 'sync')
170
- fail('"' + area + '" is kept on this PC on purpose and is not removed here.', area === 'accounts' ? 'Remove a saved login with: sandbox account remove <name>' : usage);
171
- if (!DATA_AREAS.includes(area))
172
- fail('Unknown target "' + raw + '".', usage);
173
- if (area === 'logs' && rest.length)
174
- fail('Remove all logs ("logs"), not single files.', usage);
175
- if (rest.length > (area === 'tools' && rest[0]?.toLowerCase() === 'agents' ? 2 : 1))
176
- fail('Refusing "' + raw + '": too deep.', usage);
177
- return { target, path: path.join(dataPath, area, ...rest), root: dataPath, ...(area === 'state' ? { warning: LOGIN_WARNING } : {}) };
178
- });
179
- // "all" covers everything; otherwise drop targets inside another target (tools + tools/go = tools).
180
- const all = resolved.find((t) => t.target === 'all');
181
- if (all)
182
- return [all, { target: 'launches', path: path.join(storageRoot, 'launches'), root: storageRoot }];
183
- const unique = _.uniqBy(resolved, (t) => t.path.toLowerCase());
184
- return unique.filter((t) => !unique.some((o) => o !== t && isInsideOrEqual(o.path, t.path)));
185
- };
186
- /** Asks the user to type `expected` (a stronger confirmation than y/N). */
187
- const askTyped = async (question, expected) => {
188
- if (!process.stdin.isTTY)
189
- return false;
190
- const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
191
- const answer = await new Promise((resolve) => rl.question(question + ' Type "' + expected + '" to confirm: ', resolve));
192
- rl.close();
193
- return answer.trim().toLowerCase() === expected;
194
- };
195
- export const dataClean = async (ctx) => {
196
- const targets = resolveCleanTargets(ctx.options.positionals.slice(1), ctx.dataPath, ctx.storageRoot);
197
- if (isSandboxRunning())
198
- fail('A Windows Sandbox is running, and it uses these folders.', 'Close it first (sandbox stop), then run this again.');
199
- // Every folder from the root down to the target's parent must be real; a link in place of the target is removed itself.
200
- for (const t of targets)
201
- assertNoLinks(t.root, path.dirname(t.path));
202
- const present = targets.filter((t) => fs.existsSync(t.path) || isLink(t.path));
203
- if (!present.length) {
204
- console.log('Nothing to remove: ' + targets.map((t) => t.target).join(', ') + ' do(es) not exist.');
205
- return 0;
206
- }
207
- const sized = present.map((t) => ({ ...t, bytes: sizeOf(t.path) }));
208
- const total = _.sumBy(sized, 'bytes');
209
- table(sized.map((t) => [' ' + t.target, humanBytes(t.bytes), t.path]));
210
- for (const t of sized)
211
- if (t.warning)
212
- console.log('Warning: ' + t.target + ' ' + t.warning + '.');
213
- const yes = Boolean(ctx.options.yes);
214
- if (!yes) {
215
- const ok = sized.some((t) => t.target === 'all')
216
- ? await askTyped('This cannot be undone; the next sandbox starts from scratch and reinstalls everything.', 'all')
217
- : await askYesNo('Remove ' + (sized.length === 1 ? 'this' : 'these ' + sized.length) + ' (' + humanBytes(total) + ')?');
218
- if (!ok) {
219
- console.log('Nothing removed.' + (process.stdin.isTTY ? '' : ' Pass --yes to confirm without a prompt.'));
220
- return 1;
221
- }
222
- }
223
- const failed = [];
224
- for (const t of sized) {
225
- try {
226
- removeTree(t.path, t.root);
227
- }
228
- catch (e) {
229
- failed.push(t.target + ' (' + (e instanceof Error ? e.message : String(e)) + ')');
230
- }
231
- }
232
- const freed = total - _.sumBy(sized, (t) => sizeOf(t.path));
233
- console.log('Freed ' + humanBytes(freed) + '. ' + (sized.some((t) => t.root === ctx.dataPath || t.target === 'all') ? 'The next sandbox reinstalls what it needs.' : ''));
234
- if (failed.length)
235
- fail('Could not remove everything: ' + failed.join('; '), 'Close programs using those folders and run the same command again.');
236
- return 0;
237
- };
238
- /** `sandbox data [info|clean] [targets...]`. */
239
- export const data = (ctx) => {
240
- const [action = 'info'] = ctx.options.positionals;
241
- switch (action) {
242
- case 'info':
243
- case 'show':
244
- case 'list': return dataInfo(ctx);
245
- case 'clean':
246
- case 'remove': return dataClean(ctx);
247
- default: return fail('Unknown data action "' + action + '".', 'Use: sandbox data (what is stored) or sandbox data clean <target...>');
248
- }
249
- };