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
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Josh DiDuca
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -4,8 +4,8 @@
4
4
 
5
5
  **A throwaway Windows machine for every project, with or without an AI agent.**
6
6
 
7
- [![Release](https://img.shields.io/github/v/release/JoshDiDuca/agent-sandbox?label=release)](https://github.com/JoshDiDuca/agent-sandbox/releases/latest)
8
- [![CI](https://github.com/JoshDiDuca/agent-sandbox/actions/workflows/ci.yml/badge.svg)](https://github.com/JoshDiDuca/agent-sandbox/actions/workflows/ci.yml)
7
+ [![Release](https://img.shields.io/github/v/release/JoshDiDuca/windows-development-sandbox?label=release)](https://github.com/JoshDiDuca/windows-development-sandbox/releases/latest)
8
+ [![CI](https://github.com/JoshDiDuca/windows-development-sandbox/actions/workflows/ci.yml/badge.svg)](https://github.com/JoshDiDuca/windows-development-sandbox/actions/workflows/ci.yml)
9
9
  ![Windows 10/11 Pro, Enterprise, Education](https://img.shields.io/badge/Windows-10%20%7C%2011%20Pro-0078D4)
10
10
  ![MIT](https://img.shields.io/badge/license-MIT-green)
11
11
 
@@ -18,19 +18,20 @@ on your PC is reachable. Close it and it's gone. Your project, tools, databases
18
18
  ## Install
19
19
 
20
20
  ```powershell
21
- irm https://github.com/JoshDiDuca/agent-sandbox/releases/latest/download/install.ps1 | iex
21
+ irm https://github.com/JoshDiDuca/windows-development-sandbox/releases/latest/download/install.ps1 | iex
22
22
  ```
23
23
 
24
24
  It checks your PC, offers to turn on Windows Sandbox, and installs everything. It uses your Node.js 20+ if you have it,
25
25
  otherwise a private copy just for this tool. Nothing is installed system-wide.
26
- Needs Windows 10/11 **Pro, Enterprise or Education**. [Other ways to install](docs/install.md)
26
+ Needs Windows 10/11 **Pro, Enterprise or Education**. Already have Node.js 20+? `npm install -g windows-development-sandbox`
27
+ works too. [Other ways to install](docs/install.md)
27
28
 
28
29
  ## Use
29
30
 
30
31
  ```powershell
31
32
  cd C:\code\my-app
32
33
 
33
- sandbox # menu: start an agent, a plain sandbox, diagnostics, cleanup ...
34
+ sandbox # the menu: start agents, sessions, apps, every setting, diagnostics ...
34
35
  sandbox claude # Claude Code in a sandbox for this folder (or: claude-sandbox)
35
36
  sandbox claude -t # ... in this terminal (Ctrl+] detaches, the session keeps running)
36
37
  sandbox start # just the sandbox, no agent
@@ -48,26 +49,42 @@ The first start downloads what the project needs (a few minutes, once). After th
48
49
  |---|---|
49
50
  | **Safe by default** | The agent sees only your project folder. Credentials are stripped before anything is copied in, your LAN is blocked, and nothing the sandbox writes can run on your PC. |
50
51
  | **Languages** | Node, Python, Rust, C/C++ (GCC or MSVC), .NET (incl. .NET Framework targeting), Go, Java, Ruby, PHP, Deno, Bun, PowerShell 7, with pnpm, yarn, Volta, uv, pyenv, Maven, Gradle, Composer, gh ... |
51
- | **Databases** | PostgreSQL, MySQL, MongoDB, Redis and DynamoDB Local with a web UI, started only when the project uses them |
52
+ | **Apps and tools** | VS Code (set up for your languages, with their extensions) and Windows Terminal, plus 60 optional apps and tools by category: DBeaver, pgAdmin, Bruno, Godot, Blender, kubectl, jq, ripgrep ... and programs of your own |
53
+ | **Databases** | PostgreSQL, MySQL, MongoDB, Redis and DynamoDB Local with a web UI, started when the project uses them, or any time with `--database` / `sandbox db` |
52
54
  | **Agents** | Claude Code, Codex, Gemini, opencode, Qwen, Crush, Copilot, Kilo, Amp, Cline, Continue, Kimi, Aider, DeepSeek agents |
53
55
  | **Smart** | Detects what the project needs from its files, respects version files, installs in parallel and reuses everything |
56
+ | **Several projects** | `sandbox claude` from another project joins the running sandbox: its own folder, tools, versions, databases and environment, set up on demand. Start several agents at once (`--session claude@A --session codex@B`, or the menu) and attach to any of them from any terminal |
57
+ | **Agent commands** (Beta) | `sandbox agent-commands on`: typing `claude`, `codex` ... in any folder starts it in a hidden sandbox and attaches your terminal |
54
58
  | **Feels like home** | Your desktop look, Claude settings, MCP servers and conversation history come along; history syncs back |
55
59
 
56
60
  ## Commands
57
61
 
58
62
  | Command | |
59
63
  |---|---|
60
- | `sandbox` | the interactive menu: repeat your last command, start agents, every option, and all settings |
64
+ | `sandbox` | the menu, a full-screen app: start agents, attach to sessions, pick apps, edit every setting (yours and the project's), all commands, with search |
61
65
  | `sandbox <agent>`, `claude-sandbox` | start an agent; `-t` for this terminal, `--headless` for no window |
62
66
  | `sandbox start` | the sandbox without an agent |
63
- | `sandbox attach` / `sessions` / `status` | work with a running sandbox |
67
+ | `sandbox attach` / `sessions` / `status` | work with a running sandbox (this folder's project first) |
68
+ | `sandbox projects` | the projects a sandbox can open without a restart: roots, `all`, exclude |
69
+ | `sandbox db [start\|stop <name>]` | list, start or stop databases (`sbx-db` inside) |
64
70
  | `sandbox exec -- <cmd>` | run a command inside |
71
+ | `sandbox agent-commands on\|off` | (Beta) make the agents installed on this PC start in a sandbox |
72
+ | `sandbox --version` | the installed version |
65
73
  | `sandbox stop` / `hide` / `show` | shut down, hide or show the window |
66
74
  | `sandbox data` / `data clean` | what's stored and how big, and freeing space |
67
75
  | `sandbox setup` / `doctor` / `repair` | check this PC, see what will be installed, fix common problems |
68
76
 
69
77
  All commands and options: [docs/commands.md](docs/commands.md)
70
78
 
79
+ ## Known gaps
80
+
81
+ Adding a folder to a RUNNING sandbox needs Windows 11 24H2+ with the updated Windows Sandbox (`wsb share`, untested).
82
+ On older Windows: folders inside a mapped project root (`sandbox projects roots add <folder>`) open instantly;
83
+ anything else offers a restart (your files, tools, databases and logins are kept; the sessions can be reopened).
84
+
85
+ To get `wsb`: Settings > Windows Update, turn on "Get the latest updates as soon as they're available" (or use the
86
+ Windows 11 Installation Assistant), then update Windows Sandbox from the Microsoft Store. Check with `wsb --version`.
87
+
71
88
  ## Documentation
72
89
 
73
90
  - [Install](docs/install.md): requirements, other ways to install, upgrading
@@ -3,10 +3,25 @@
3
3
  "defaultHarness": "claude",
4
4
  "guestWorkspace": "auto",
5
5
  "readOnly": false,
6
+ "workspaceFilter": {
7
+ "enabled": false,
8
+ "exclude": [],
9
+ "include": []
10
+ },
11
+ "audit": {
12
+ "enabled": false,
13
+ "days": 14,
14
+ "maxMb": 100,
15
+ "processes": true,
16
+ "files": true
17
+ },
6
18
  "mappings": [],
7
19
  "sandbox": {
8
20
  "memoryMb": "auto",
9
21
  "maxMemoryMb": 32768,
22
+ "maxMemoryPercent": 80,
23
+ "cpuLimit": 80,
24
+ "pageFileMb": 16384,
10
25
  "reserveHostMb": 8192,
11
26
  "vGpu": false,
12
27
  "networking": true,
@@ -15,15 +30,23 @@
15
30
  "videoInput": false,
16
31
  "printerRedirection": false,
17
32
  "protectedClient": true,
18
- "headless": false
33
+ "headless": false,
34
+ "keepAwake": true
19
35
  },
20
36
  "storage": {
21
37
  "root": "%LOCALAPPDATA%\\AgentSandbox",
22
38
  "persistAgentState": true,
23
- "dataName": "default"
39
+ "dataName": "default",
40
+ "markSandboxFiles": true,
41
+ "warnDataGb": 50
24
42
  },
25
43
  "network": {
26
- "blockPrivateRanges": true
44
+ "blockPrivateRanges": true,
45
+ "allowOnly": [],
46
+ "blockHosts": [],
47
+ "forwardPorts": [],
48
+ "dns": [],
49
+ "proxy": ""
27
50
  },
28
51
  "provisioning": {
29
52
  "copyFromHost": true,
@@ -35,8 +58,14 @@
35
58
  },
36
59
  "terminal": {
37
60
  "enabled": true
61
+ },
62
+ "conpty": {
63
+ "enabled": true
38
64
  }
39
65
  },
66
+ "downloads": {
67
+ "requireChecksum": false
68
+ },
40
69
  "toolchains": {
41
70
  "node": {
42
71
  "version": "host",
@@ -130,7 +159,10 @@
130
159
  "vulkan": false
131
160
  },
132
161
  "vscode": {
133
- "enabled": true
162
+ "enabled": true,
163
+ "setup": true,
164
+ "recommended": true,
165
+ "extensions": []
134
166
  },
135
167
  "environment": {}
136
168
  },
@@ -170,6 +202,10 @@
170
202
  "auto": false,
171
203
  "autoHide": false
172
204
  },
205
+ "agentCommands": {
206
+ "enabled": false,
207
+ "agents": "auto"
208
+ },
173
209
  "secrets": {
174
210
  "strip": true,
175
211
  "allow": [],
@@ -179,6 +215,10 @@
179
215
  "personalization": {
180
216
  "enabled": true
181
217
  },
218
+ "apps": {
219
+ "install": [],
220
+ "custom": {}
221
+ },
182
222
  "claudeProfile": {
183
223
  "enabled": true,
184
224
  "hostDir": "auto",
@@ -194,7 +234,9 @@
194
234
  "copyCredentials": false,
195
235
  "overwrite": true,
196
236
  "syncHistory": true,
197
- "syncClaudeMem": true
237
+ "historyScope": "project",
238
+ "syncClaudeMem": true,
239
+ "syncClaudeMemBack": false
198
240
  },
199
241
  "harnesses": {
200
242
  "claude": {
@@ -328,5 +370,13 @@
328
370
  },
329
371
  "hooks": {
330
372
  "failFast": false
373
+ },
374
+ "projects": {
375
+ "all": false,
376
+ "exclude": [],
377
+ "roots": [],
378
+ "askToAddRoot": true,
379
+ "declinedRoots": [],
380
+ "wsbShare": true
331
381
  }
332
382
  }
package/dist/api.js CHANGED
@@ -1,7 +1,8 @@
1
1
  // Programmatic API: `import { sandbox } from 'windows-development-sandbox'`. Same safety model as the CLI: the host only sends the
2
2
  // request kinds the guest daemon accepts, and everything coming back is validated data.
3
3
  import path from 'node:path';
4
- import { attachTerminal, execInSandbox, pickSession, pingSandbox, requestSession, restartSessions, waitForReady, waitForSession } from './host/channel.js';
4
+ import { attachTerminal } from './host/attach.js';
5
+ import { execInSandbox, pickSession, pingSandbox, requestSession, restartSessions, waitForReady, waitForSession } from './host/channel.js';
5
6
  import { loadConfig } from './core/config.js';
6
7
  import { listSessions, readSandboxStatus } from './shared/rundir.js';
7
8
  import { isSandboxRunning } from './host/platform.js';
@@ -25,7 +25,30 @@ export interface CliOptions {
25
25
  yes: boolean;
26
26
  timeout: number;
27
27
  days: number;
28
+ /** restart: every session, not only this folder's project's. */
29
+ all: boolean;
30
+ /** launch --session <agent>@<folder> (repeatable): several sessions at once, folders made absolute. */
31
+ sessions: SessionWant[];
32
+ /** audit: only events of this kind, and containing this text. */
33
+ kind?: string;
34
+ grep?: string;
28
35
  }
36
+ /** One session to start: an agent in a folder, with arguments of its own (after the ones given after --). */
37
+ export interface SessionWant {
38
+ harness: string;
39
+ folder: string;
40
+ args?: string[];
41
+ }
42
+ /** Splits a command line like a shell: "quoted words" and 'quoted words' stay together. */
43
+ export declare const splitArgs: (text: string) => string[];
44
+ /**
45
+ * `<agent>@<folder>` (the folder may contain '@': only the first one splits), `<agent>` alone = the current folder,
46
+ * and `|<arguments>` for that session's agent only ('|' cannot be in a Windows path). Folders become absolute against
47
+ * `cwd`. Pure; validate.ts checks that the agent and folder exist.
48
+ */
49
+ export declare const parseSessionWant: (input: string, cwd?: string) => SessionWant;
50
+ /** This package's version (this file is dist/cli/args.js, two folders below package.json). */
51
+ export declare const packageVersion: () => string;
29
52
  /** Every command, its options and help text, from manifest.ts. Actions only record what was parsed. */
30
53
  export declare const buildProgram: (record: (name: string, cmd: Command) => void) => Command;
31
54
  /** Parses argv into the command name and options. Throws commander errors for unknown commands/options. */
package/dist/cli/args.js CHANGED
@@ -1,8 +1,35 @@
1
1
  // Command-line parsing with commander. parseCli() only parses (no side effects), so it is easy to test; cli/index.ts
2
2
  // dispatches the result. sandbox claude & co parse as `launch`: every option launch does not own goes to the agent, in order.
3
+ import path from 'node:path';
4
+ import { fileURLToPath } from 'node:url';
3
5
  import { Command, InvalidArgumentError, Option } from 'commander';
4
- import { fail } from '../core/util.js';
6
+ import { z } from 'zod';
7
+ import { fail, tryReadJson } from '../core/util.js';
8
+ import { c } from './colors.js';
5
9
  import { COMMANDS } from './manifest.js';
10
+ /** Splits a command line like a shell: "quoted words" and 'quoted words' stay together. */
11
+ export const splitArgs = (text) => [...text.matchAll(/"([^"]*)"|'([^']*)'|(\S+)/g)].map((m) => m[1] ?? m[2] ?? m[3]);
12
+ /**
13
+ * `<agent>@<folder>` (the folder may contain '@': only the first one splits), `<agent>` alone = the current folder,
14
+ * and `|<arguments>` for that session's agent only ('|' cannot be in a Windows path). Folders become absolute against
15
+ * `cwd`. Pure; validate.ts checks that the agent and folder exist.
16
+ */
17
+ export const parseSessionWant = (input, cwd = process.cwd()) => {
18
+ const bar = input.indexOf('|');
19
+ const text = bar < 0 ? input : input.slice(0, bar);
20
+ const args = bar < 0 ? [] : splitArgs(input.slice(bar + 1));
21
+ const at = text.indexOf('@');
22
+ const harness = (at < 0 ? text : text.slice(0, at)).trim();
23
+ const folder = at < 0 ? '' : text.slice(at + 1).trim();
24
+ if (!harness)
25
+ fail('--session "' + text + '" names no agent.', 'Use --session <agent>@<folder>, e.g. --session claude@C:\\code\\api (the folder defaults to this one).');
26
+ return { harness, folder: path.resolve(cwd, folder || '.'), ...(args.length ? { args } : {}) };
27
+ };
28
+ /** This package's version (this file is dist/cli/args.js, two folders below package.json). */
29
+ export const packageVersion = () => {
30
+ const file = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', '..', 'package.json');
31
+ return z.object({ version: z.string() }).safeParse(tryReadJson(file)).data?.version ?? 'unknown';
32
+ };
6
33
  /** Reserved spelling for our launch options that can never clash with an agent's flags: --sbx-terminal, ... */
7
34
  const SBX_PREFIX = '--sbx-';
8
35
  const positiveNumber = (value) => {
@@ -28,8 +55,11 @@ const toOption = (o) => {
28
55
  export const buildProgram = (record) => {
29
56
  const program = new Command('sandbox')
30
57
  .description('A disposable Windows Sandbox for development, with or without an AI agent, for the folder you are in. Run it with no arguments for the menu.')
58
+ .version(packageVersion(), '-v, --version', 'show the version')
31
59
  .enablePositionalOptions()
32
- .showHelpAfterError('(run with --help for usage)')
60
+ .showHelpAfterError(' Fix: run the command with --help to see how to use it.')
61
+ .configureOutput({ outputError: (text, write) => write(c.red('Error: ') + text.replace(/^error: /, '').replace(/^./, (ch) => ch.toUpperCase())) })
62
+ .addHelpText('after', '\nPut --config <file> before or after the command to use another settings file.\nExamples:\n sandbox the menu\n sandbox claude -t start Claude and attach this terminal\n sandbox data clean logs delete the saved logs\n sandbox exec -- npm test run a command in the running sandbox')
33
63
  .exitOverride();
34
64
  for (const spec of COMMANDS) {
35
65
  const cmd = program.command(spec.name, { hidden: spec.hidden }).description(spec.summary).option('--config <file>', 'config file (default: ~/.agent-sandbox/config.json)');
@@ -101,11 +131,15 @@ export const parseCli = (argv, wrapper = false) => {
101
131
  follow: Boolean(o.follow),
102
132
  json: Boolean(o.json),
103
133
  yes: Boolean(o.yes),
134
+ all: Boolean(o.all),
135
+ sessions: (o.session ?? []).map((s) => parseSessionWant(s)),
104
136
  timeout: o.timeout ?? 600,
105
- days: o.days ?? 7,
137
+ days: o.days ?? (name === 'audit' ? 1 : 7),
138
+ kind: o.kind,
139
+ grep: o.grep,
106
140
  };
107
141
  };
108
142
  const defaults = () => ({
109
143
  command: '', positionals: [], passthrough: [], scripts: [], databases: [], terminal: false, newSession: false, noAgent: false, trustConfig: false, noLocalConfig: false,
110
- personal: false, fromHost: false, noRestart: false, follow: false, json: false, yes: false, timeout: 600, days: 7,
144
+ personal: false, fromHost: false, noRestart: false, follow: false, json: false, yes: false, all: false, sessions: [], timeout: 600, days: 7,
111
145
  });
@@ -0,0 +1,24 @@
1
+ /** The colour policy as a pure function (tested); `isTTY` is that of the stream being written to. */
2
+ export declare const colorEnabled: (env: NodeJS.ProcessEnv, isTTY: boolean) => boolean;
3
+ export declare const c: {
4
+ bold: (text: string) => string;
5
+ dim: (text: string) => string;
6
+ red: (text: string) => string;
7
+ green: (text: string) => string;
8
+ yellow: (text: string) => string;
9
+ cyan: (text: string) => string;
10
+ };
11
+ /** Removes colour codes (for measuring or comparing text). */
12
+ export declare const stripAnsi: (text: string) => string;
13
+ /** Cuts `text` to `max` visible characters, ending in an ellipsis (plain text only). */
14
+ export declare const shorten: (text: string, max: number) => string;
15
+ /** Cuts the middle out of a long path or id so both ends stay readable. */
16
+ export declare const shortenMiddle: (text: string, max: number) => string;
17
+ /** 1536 -> "1.5 KB" is in the data command; this is "3 min ago" for the tables. */
18
+ export declare const ago: (then: number | string | Date, now?: number) => string;
19
+ /** Width to lay text out in (terminal columns, 80 when unknown, never absurdly small). */
20
+ export declare const termWidth: () => number;
21
+ /** Each menu page starts on a clean screen (answered prompts would otherwise pile up above it). */
22
+ export declare const clearScreen: () => void;
23
+ /** Rows of a list that fit the terminal (leaving room for the prompt and the help line). */
24
+ export declare const pageSizeFor: (wanted: number) => number;
@@ -0,0 +1,42 @@
1
+ // ANSI colours for terminal output (one place, so menus, errors and warnings agree).
2
+ // Colour is on only for a terminal that wants it: not with NO_COLOR, TERM=dumb or piped output; FORCE_COLOR turns it on.
3
+ /** The colour policy as a pure function (tested); `isTTY` is that of the stream being written to. */
4
+ export const colorEnabled = (env, isTTY) => {
5
+ if (env.NO_COLOR)
6
+ return false;
7
+ if (env.FORCE_COLOR !== undefined && env.FORCE_COLOR !== '')
8
+ return env.FORCE_COLOR !== '0' && env.FORCE_COLOR !== 'false';
9
+ return isTTY && env.TERM !== 'dumb';
10
+ };
11
+ const paint = (code) => (text) => (colorEnabled(process.env, Boolean(process.stdout.isTTY)) ? '\x1b[' + code + 'm' + text + '\x1b[0m' : text);
12
+ export const c = { bold: paint(1), dim: paint(2), red: paint(31), green: paint(32), yellow: paint(33), cyan: paint(36) };
13
+ /** Removes colour codes (for measuring or comparing text). */
14
+ export const stripAnsi = (text) => text.replace(/\x1b\[[0-9;]*m/g, '');
15
+ /** Cuts `text` to `max` visible characters, ending in an ellipsis (plain text only). */
16
+ export const shorten = (text, max) => (max < 2 || text.length <= max ? text : text.slice(0, max - 1) + '…');
17
+ /** Cuts the middle out of a long path or id so both ends stay readable. */
18
+ export const shortenMiddle = (text, max) => {
19
+ if (max < 5 || text.length <= max)
20
+ return text;
21
+ const keep = max - 1;
22
+ const head = Math.ceil(keep / 2);
23
+ return text.slice(0, head) + '…' + text.slice(text.length - (keep - head));
24
+ };
25
+ /** 1536 -> "1.5 KB" is in the data command; this is "3 min ago" for the tables. */
26
+ export const ago = (then, now = Date.now()) => {
27
+ const secs = Math.max(0, Math.round((now - new Date(then).getTime()) / 1000));
28
+ if (secs < 45)
29
+ return 'just now';
30
+ if (secs < 3600)
31
+ return Math.round(secs / 60) + ' min ago';
32
+ if (secs < 86400)
33
+ return Math.round(secs / 3600) + ' h ago';
34
+ return Math.round(secs / 86400) + ' d ago';
35
+ };
36
+ /** Width to lay text out in (terminal columns, 80 when unknown, never absurdly small). */
37
+ export const termWidth = () => Math.max(40, process.stdout.columns ?? 80);
38
+ /** Each menu page starts on a clean screen (answered prompts would otherwise pile up above it). */
39
+ export const clearScreen = () => { if (process.stdout.isTTY)
40
+ process.stdout.write('\x1b[2J\x1b[3J\x1b[H'); };
41
+ /** Rows of a list that fit the terminal (leaving room for the prompt and the help line). */
42
+ export const pageSizeFor = (wanted) => Math.max(5, Math.min(wanted, (process.stdout.rows ?? 30) - 6));
@@ -3,7 +3,7 @@ import { activateAccount, listAccounts, removeAccount, saveAccount, setDefaultAc
3
3
  import { restartSessions, runningSessions } from '../../host/channel.js';
4
4
  import { hostClaudeDir, hostGlobalStateFile } from '../../host/claude-profile.js';
5
5
  import { isSandboxRunning } from '../../host/platform.js';
6
- import { fail } from '../../core/util.js';
6
+ import { fail, safeText } from '../../core/util.js';
7
7
  import { printJson, sandboxAlive, table } from './context.js';
8
8
  const label = (a) => '"' + a.name + '"' + (a.email ? ' (' + a.email + ')' : '');
9
9
  /** This PC's Claude login location (config folder + global state file). */
@@ -27,7 +27,7 @@ const use = async (ctx, name) => {
27
27
  console.log('Sandbox now uses ' + label(activateAccount(ctx.storageRoot, ctx.dataPath, name)) + '.');
28
28
  const claudeRunning = isSandboxRunning() && runningSessions(ctx.dataPath).some((s) => s.harness === 'claude');
29
29
  if (claudeRunning && !ctx.options.noRestart)
30
- console.log((await restartSessions(ctx.dataPath, 'claude', sandboxAlive)).message + ' with --continue; the conversation carries on under the new account.');
30
+ console.log(safeText((await restartSessions(ctx.dataPath, 'claude', sandboxAlive)).message) + ' with --continue; the conversation carries on under the new account.');
31
31
  return 0;
32
32
  };
33
33
  export const account = async (ctx) => {
@@ -0,0 +1,6 @@
1
+ import type { Config } from '../../core/types.js';
2
+ import { type Reconciled } from '../../host/agent-commands.js';
3
+ import { type Context } from './context.js';
4
+ /** Brings this PC in line with agentCommands and says what changed (used after on/off, settings and launch). */
5
+ export declare const syncAgentCommands: (ctx: Context, config: Config, quiet?: boolean) => Reconciled | null;
6
+ export declare const agentCommandsCommand: (ctx: Context) => number;
@@ -0,0 +1,61 @@
1
+ // `sandbox agent-commands [status|on|off]` (Beta): typing claude, codex ... on this PC starts them in a hidden sandbox.
2
+ import fs from 'node:fs';
3
+ import path from 'node:path';
4
+ import { loadConfig, userConfigPath } from '../../core/config.js';
5
+ import { fail } from '../../core/util.js';
6
+ import { agentCommands, commandsDir, reconcileAgentCommands } from '../../host/agent-commands.js';
7
+ import { insideSandbox } from '../../host/platform.js';
8
+ import { writeFileAtomic } from '../../shared/rundir.js';
9
+ import { c } from '../colors.js';
10
+ import { editConfigText } from '../menu/settings/config-file.js';
11
+ import { table } from './context.js';
12
+ const entryOf = (ctx) => path.join(ctx.packageRoot, 'dist', 'bin', 'sandbox.js');
13
+ /** Brings this PC in line with agentCommands and says what changed (used after on/off, settings and launch). */
14
+ export const syncAgentCommands = (ctx, config, quiet = false) => {
15
+ if (insideSandbox())
16
+ return null;
17
+ const result = reconcileAgentCommands(config, ctx.storageRoot, process.execPath, entryOf(ctx));
18
+ if (!result.changed || quiet)
19
+ return result;
20
+ if (result.on) {
21
+ console.log('Agent commands (Beta) are on for: ' + (result.commands.map((a) => a.command).join(', ') || 'no installed agents found'));
22
+ console.log(c.dim('Open a new terminal, then type e.g. claude in any project folder. Run the real one: set SANDBOX_AGENT_DIRECT=1'));
23
+ }
24
+ else
25
+ console.log('Agent commands are off: claude, codex ... run on this PC again (open a new terminal).');
26
+ return result;
27
+ };
28
+ export const agentCommandsCommand = (ctx) => {
29
+ if (insideSandbox())
30
+ fail('Agent commands change your PC\'s PATH, so they are set up from your PC, not inside the sandbox.', 'Run sandbox agent-commands on in a terminal on your PC.');
31
+ const action = ctx.options.positionals[0] ?? 'status';
32
+ if (action === 'status') {
33
+ const config = ctx.loaded.config;
34
+ const found = agentCommands(config, ctx.storageRoot);
35
+ console.log('Agent commands (Beta): ' + (config.agentCommands.enabled ? c.green('on') : 'off') + c.dim(' (' + commandsDir(ctx.storageRoot) + ')'));
36
+ if (found.length)
37
+ table(found.map((a) => [a.command, 'sandboxed ' + a.harness + (config.agentCommands.enabled ? '' : ' when on'), c.dim('real: ' + a.real)]));
38
+ else
39
+ console.log(c.dim('No agents found on this PC (claude, codex, gemini ... on your PATH).'));
40
+ if (!config.agentCommands.enabled)
41
+ console.log(c.dim('Turn on with: sandbox agent-commands on'));
42
+ return 0;
43
+ }
44
+ if (action !== 'on' && action !== 'off')
45
+ fail('Unknown action "' + action + '".', 'Use: sandbox agent-commands [status|on|off]');
46
+ const file = ctx.loaded.configPath ?? userConfigPath();
47
+ const text = fs.existsSync(file) ? fs.readFileSync(file, 'utf8') : '';
48
+ const edited = editConfigText(text, ['agentCommands', 'enabled'], action === 'on' ? true : undefined);
49
+ if ('problems' in edited)
50
+ fail('Could not change ' + file + ': ' + edited.problems.join('; '), 'Fix the file with sandbox config check, then try again.');
51
+ writeFileAtomic(file, edited.text);
52
+ const result = syncAgentCommands(ctx, loadConfig(file).config, true);
53
+ if (result?.on) {
54
+ console.log('Agent commands (Beta) are on: ' + (result.commands.map((a) => a.command).join(', ') || 'no installed agents found yet'));
55
+ console.log(c.dim('Open a new terminal, then type e.g. claude in a project folder: it starts in a hidden sandbox and attaches.'));
56
+ console.log(c.dim('Run the real one on this PC: set SANDBOX_AGENT_DIRECT=1 (PowerShell: $env:SANDBOX_AGENT_DIRECT=1). Turn off: sandbox agent-commands off'));
57
+ }
58
+ else
59
+ console.log('Agent commands are off: claude, codex ... run on this PC again. Open a new terminal.');
60
+ return 0;
61
+ };
@@ -14,6 +14,8 @@ export declare const table: (rows: string[][]) => void;
14
14
  /** Prints `value` as JSON when --json was given; returns whether it did. */
15
15
  export declare const printJson: (ctx: Context, value: unknown) => boolean;
16
16
  export declare const sandboxAlive: () => boolean;
17
+ /** For commands that control the sandbox from your PC: inside the sandbox they make no sense. */
18
+ export declare const requireOnPc: (what: string) => void;
17
19
  export declare const requireRunning: (hint?: string) => void;
18
20
  /** Maps a folder on this PC to its path inside the running sandbox (only folders inside the mapped workspace exist there). */
19
21
  export declare const guestPathFor: (hostDir: string, workspaceHost: string, guestWorkspace: string) => string;
@@ -36,11 +36,15 @@ export const table = (rows) => {
36
36
  };
37
37
  /** Prints `value` as JSON when --json was given; returns whether it did. */
38
38
  export const printJson = (ctx, value) => {
39
+ // JSON.stringify leaves C1 controls (U+0080-U+009F) as they are; text from the sandbox must not reach a terminal raw.
39
40
  if (ctx.options.json)
40
- console.log(JSON.stringify(value, null, 2));
41
+ console.log(JSON.stringify(value, null, 2).replace(/[\u0080-\u009f]/g, (ch) => '\\u' + ch.charCodeAt(0).toString(16).padStart(4, '0')));
41
42
  return ctx.options.json;
42
43
  };
43
44
  export const sandboxAlive = () => isSandboxRunning();
45
+ /** For commands that control the sandbox from your PC: inside the sandbox they make no sense. */
46
+ export const requireOnPc = (what) => { if (insideSandbox())
47
+ fail('You are inside the sandbox already, so "sandbox ' + what + '" has nothing to control.', 'Run it from a terminal on your PC.'); };
44
48
  export const requireRunning = (hint = '') => { if (!isSandboxRunning())
45
49
  fail('No Windows Sandbox is running.', hint || 'Start one with sandbox claude.'); };
46
50
  /** Maps a folder on this PC to its path inside the running sandbox (only folders inside the mapped workspace exist there). */
@@ -0,0 +1,15 @@
1
+ import { type Context } from '../context.js';
2
+ export interface CleanTarget {
3
+ /** The target as normalised (forward slashes), e.g. "tools/go". */
4
+ target: string;
5
+ path: string;
6
+ /** Folder the target must stay inside, with no links between the two. */
7
+ root: string;
8
+ warning?: string;
9
+ }
10
+ /**
11
+ * Turns `sandbox data clean` arguments into folders. Pure (no disk access); throws a UserError for anything that is
12
+ * not a plain relative target inside the data folder: absolute paths, drive letters, `..`, wildcards, unknown areas.
13
+ */
14
+ export declare const resolveCleanTargets: (inputs: string[], dataPath: string, storageRoot: string) => CleanTarget[];
15
+ export declare const dataClean: (ctx: Context) => Promise<number>;