windows-development-sandbox 1.16.0 → 1.17.3

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 (64) hide show
  1. package/README.md +92 -92
  2. package/config.example.json +6 -0
  3. package/dist/app/features/access/access.run.js +1 -1
  4. package/dist/bin/agent-sandbox.js +2 -2
  5. package/dist/bin/{chunk-7EXDUNE7.js → chunk-QLGGAG3D.js} +1 -1
  6. package/dist/bin/{chunk-HIC4CUMY.js → chunk-REE3EMHD.js} +73 -16
  7. package/dist/bin/{chunk-PXTLKIV4.js → chunk-XYUVIVJT.js} +1 -1
  8. package/dist/bin/claude-host.js +2 -2
  9. package/dist/bin/claude-sbx.js +2 -2
  10. package/dist/bin/codex-sbx.js +2 -2
  11. package/dist/bin/gemini-sbx.js +2 -2
  12. package/dist/bin/sandbox.js +2 -2
  13. package/dist/bin/sbx-hide.js +2 -2
  14. package/dist/bin/sbx-show.js +2 -2
  15. package/dist/cli/commands/web.js +1 -1
  16. package/dist/core/config/defaults.js +1 -0
  17. package/dist/core/detect/toolchains.d.ts +1 -0
  18. package/dist/core/detect/toolchains.js +7 -0
  19. package/dist/core/schema/config.d.ts +21 -0
  20. package/dist/core/schema/sandbox.js +1 -1
  21. package/dist/core/schema/toolchains.d.ts +6 -0
  22. package/dist/core/schema/toolchains.js +10 -0
  23. package/dist/guest/agents/agent-files.d.ts +6 -0
  24. package/dist/guest/agents/agent-files.js +14 -0
  25. package/dist/guest/agents/local-state.d.ts +2 -0
  26. package/dist/guest/agents/local-state.js +13 -1
  27. package/dist/guest/boot/boot.js +4 -1
  28. package/dist/guest/setup/browser-gpu.d.ts +1 -0
  29. package/dist/guest/setup/browser-gpu.js +18 -0
  30. package/dist/guest/toolchains/native/rust-extras.js +3 -1
  31. package/dist/guest/toolchains/native/unreal.d.ts +9 -0
  32. package/dist/guest/toolchains/native/unreal.js +198 -0
  33. package/dist/guest/toolchains/native/vcruntime.d.ts +3 -0
  34. package/dist/guest/toolchains/native/vcruntime.js +2 -2
  35. package/dist/guest/toolchains/plan.js +10 -2
  36. package/dist/host/engines/hcs/live-folders.js +1 -1
  37. package/dist/host/github/token.js +1 -1
  38. package/dist/host/profile/accounts.js +1 -1
  39. package/dist/host/profile/agent-accounts.js +1 -1
  40. package/dist/host/profile/plugin-share.d.ts +5 -0
  41. package/dist/host/profile/plugin-share.js +22 -1
  42. package/dist/host/secrets/secret-store.d.ts +3 -3
  43. package/dist/host/secrets/secret-store.js +37 -10
  44. package/dist/host/vpn/login.js +1 -1
  45. package/dist/runtime/agent.js +16 -1
  46. package/dist/runtime/daemon.js +531 -337
  47. package/dist/runtime/db.js +17 -1
  48. package/dist/runtime/main.js +694 -472
  49. package/dist/runtime/netproxy.js +16 -1
  50. package/dist/runtime/view.js +16 -1
  51. package/dist/selftest/accounts.test.js +7 -0
  52. package/dist/selftest/agent-paths.test.js +12 -1
  53. package/dist/selftest/detect.test.js +7 -0
  54. package/dist/selftest/live-network.test.js +5 -0
  55. package/dist/selftest/support/fixtures.d.ts +6 -0
  56. package/dist/shared/channel/schema.d.ts +18 -0
  57. package/native/csharp/HcsHost/AssemblyInfo.cs +3 -3
  58. package/native/csharp/HostTools/AssemblyInfo.cs +3 -3
  59. package/native/csharp/HostTools/Program.cs +6 -1
  60. package/native/csharp/HostTools/Protect.cs +41 -0
  61. package/native/csharp/StorageHelper/AssemblyInfo.cs +3 -3
  62. package/package.json +1 -1
  63. package/schemas/config.schema.json +34 -1
  64. package/schemas/sandbox-config.schema.json +34 -1
package/README.md CHANGED
@@ -12,9 +12,10 @@
12
12
 
13
13
  </div>
14
14
 
15
- Run it in a project folder and you get a clean [Windows Sandbox](https://learn.microsoft.com/windows/security/application-security/application-isolation/windows-sandbox/windows-sandbox-overview)
16
- where that folder is the workspace, the tools and databases the project needs install themselves, and nothing else
17
- on your PC is reachable. Close it and it's gone. Your project, tools, databases and logins are kept for next time.
15
+ Run it in a project folder to get a clean
16
+ [Windows Sandbox](https://learn.microsoft.com/windows/security/application-security/application-isolation/windows-sandbox/windows-sandbox-overview).
17
+ The folder is the workspace, the tools and databases it needs install themselves, and the rest of your PC is out of
18
+ reach. Close it and it is gone. Your project, tools, databases and logins are kept for next time.
18
19
 
19
20
  ## Install
20
21
 
@@ -22,130 +23,129 @@ on your PC is reachable. Close it and it's gone. Your project, tools, databases
22
23
  irm https://github.com/JoshDiDuca/windows-development-sandbox/releases/latest/download/install.ps1 | iex
23
24
  ```
24
25
 
25
- It checks your PC, offers to turn on Windows Sandbox, and asks **1) Just me** or **2) Everyone on this PC** (needs
26
- admin). It brings its own private copy of Node.js; nothing else is installed system-wide, and no Start menu shortcut
27
- unless you ask for one. `sandbox update` installs newer versions (and can do it by itself), even while a sandbox runs:
28
- the sandbox keeps its version until it restarts. A version that fails to start is rolled back automatically, and
29
- `sandbox update --rollback` goes back one by hand.
26
+ The installer checks your PC, offers to turn on Windows Sandbox, and asks **1) Just me** or **2) Everyone on this PC**
27
+ (needs admin). It brings its own copy of Node.js and installs nothing else system-wide. It adds no Start menu shortcut
28
+ unless you ask.
30
29
 
31
- Needs Windows 10/11 **Pro, Enterprise or Education**. Have Node.js 20+? `npm install -g windows-development-sandbox`
32
- works too. [Scopes, options (`-Version`, `-StartMenuShortcut` ...), upgrading, uninstall](docs/install.md)
30
+ - `sandbox update` installs a newer version, and can do it by itself. A running sandbox keeps its version until it
31
+ restarts.
32
+ - A new version that fails to start is rolled back for you. `sandbox update --rollback` goes back one version by hand.
33
+
34
+ Needs Windows 10/11 **Pro, Enterprise or Education**. With Node.js 20+, `npm install -g windows-development-sandbox`
35
+ works too. More: [install options, upgrading, uninstall](docs/install.md).
33
36
 
34
37
  ## Use
35
38
 
36
39
  ```powershell
37
40
  cd C:\code\my-app
38
41
 
39
- sandbox # the menu: agents, sessions, apps, every setting, diagnostics ...
42
+ sandbox # the menu: agents, sessions, apps, settings, health ...
40
43
  sandbox claude # Claude Code in a sandbox for this folder (or: claude-sandbox)
41
- sandbox claude -t # ... in this terminal (Ctrl+] detaches, the session keeps running)
42
- sandbox start # just the sandbox, no agent
44
+ sandbox claude -t # ... in this terminal (Ctrl+] detaches; the session keeps running)
45
+ sandbox start # the sandbox, no agent
43
46
  sandbox opencode # any supported agent by name
44
47
  sandbox web open # (Beta) the web UI in your browser, signed in
45
48
  ```
46
49
 
47
- The first start downloads what the project needs (a few minutes, once). After that, starts take seconds.
50
+ The first start downloads what the project needs (a few minutes, once). Later starts take seconds.
48
51
 
49
- > `claude-sbx`, `codex-sbx`, `gemini-sbx` and `agent-sandbox` are the old command names. They still work for now; use
50
- > `sandbox <agent>` / `claude-sandbox` and `sandbox` instead.
52
+ > The old names `claude-sbx`, `codex-sbx`, `gemini-sbx` and `agent-sandbox` still work for now. Use `sandbox <agent>`
53
+ > (or `claude-sandbox`) and `sandbox` instead.
51
54
 
52
55
  ## What you get
53
56
 
54
- | | |
55
- |---|---|
56
- | **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. |
57
- | **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 ... |
58
- | **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. Agent add-ons too: rtk and Headroom (fewer tokens), ccusage, Playwright and Context7 MCP servers, claude-mem, REA. Playwright works out of the box with Edge |
59
- | **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` |
60
- | **Agents** | Claude Code, Codex, Gemini, opencode, Qwen, Crush, Copilot, Kilo, Amp, Cline, Continue, Kimi, Aider, DeepSeek agents |
61
- | **Smart** | Detects what the project needs from its files, respects version files, installs in parallel and reuses everything |
62
- | **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 |
63
- | **Picks up where you left off** | After a crash or a restart, `sandbox resume` reopens the last sessions; `sandbox restart` restarts the agents in place and they continue their conversation |
64
- | **Leaves nothing behind** | When an agent's session ends, everything it started ends with it, background servers included. The web UI's server stops when no browser uses it, and nothing of this tool keeps running on your PC once the sandbox is closed |
65
- | **GitHub, safely** | Give sandboxes a fine-grained GitHub token you made for them (`sandbox github login`, `github.shareToken`): `gh` and `git push` work inside, and the token never lands in the sandbox's files |
66
- | **Feels like home** | Your desktop look, Claude settings, MCP servers and conversation history come along; history syncs back. Logins you save (`sandbox account`) are kept encrypted for your Windows user |
57
+ | | |
58
+ | ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
59
+ | **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. |
60
+ | **Languages** | Node, Python, Rust, C/C++ (GCC or MSVC), .NET (with .NET Framework targeting), Go, Java, Ruby, PHP, Deno, Bun, PowerShell 7, Unreal Engine tools. Also pnpm, yarn, Volta, uv, pyenv, Maven, Gradle, Composer, gh ... |
61
+ | **Apps and tools** | VS Code (set up for your languages) and Windows Terminal, plus about 80 optional apps by category: DBeaver, pgAdmin, Bruno, Godot, Blender, Ghidra, kubectl, jq, ripgrep ... and your own programs. Agent add-ons: rtk and Headroom (fewer tokens), ccusage, Playwright and Context7 MCP servers, claude-mem, REA. Playwright works with Edge out of the box. |
62
+ | **Databases** | PostgreSQL, MySQL, MongoDB, Redis and DynamoDB Local (with a web UI). They start when the project uses them, or any time with `--database` or `sandbox db`. |
63
+ | **Agents** | Claude Code, Codex, Gemini, opencode, Qwen, Crush, Copilot, Kilo, Amp, Cline, Continue, Kimi, Aider and two DeepSeek agents. |
64
+ | **Smart setup** | Finds what the project needs from its files, follows its version files, installs in parallel and reuses everything. |
65
+ | **Several projects** | `sandbox claude` from another project joins the running sandbox, with that project's own folder, tools, versions, databases and environment. Start several agents at once (`--session claude@A --session codex@B`, or the menu) and attach to any of them from any terminal. |
66
+ | **Pick up again** | After a crash or restart, `sandbox resume` reopens the last sessions. `sandbox restart` restarts the agents in place, and they continue their conversations. |
67
+ | **Leaves nothing behind** | When an agent's session ends, everything it started ends too, background servers included. Nothing of this tool keeps running on your PC once the sandbox is closed. |
68
+ | **GitHub, safely** | Give sandboxes a fine-grained GitHub token made just for them (`sandbox github login`, `github.shareToken`). `gh` and `git push` then work inside, and the token is never written to the sandbox's files. |
69
+ | **Feels like home** | Your desktop look, Claude settings, MCP servers and conversation history come along, and history syncs back. Saved logins (`sandbox account`) are encrypted for your Windows user. |
67
70
 
68
71
  ## Built for heavy workloads
69
72
 
70
- The sandbox behaves like a well-run PC of its own size: under load it slows down, it does not fail, and it never takes
71
- your PC down with it. Nothing needs setting up.
72
-
73
- - **Sized to what your PC can hold.** The sandbox gets only the memory your PC can keep in RAM for it, with room kept
74
- for your PC itself (and more with vGPU on).
75
- - **Builds within a budget.** Agents see the processors and memory they may really use, and every session gets a
76
- matching number of build jobs and links, written to `run\budget.json` for agents to plan with.
77
- - **Graduated throttling.** As memory fills, a governor in the sandbox turns one dial in steps: build programs get
78
- lower CPU and memory priority, then a smaller share of the CPU, then compilers take turns while the waiting ones move
79
- to the paging file. Builds get slower; nothing is stopped or killed, and agents, shells and Windows are never touched.
80
- - **Your PC has a say.** A watchdog on your PC watches its memory, CPU and disks and asks the sandbox to ease off, at
81
- once and all the way when your PC is nearly out of memory.
82
- - **A last resort that only protects.** Only at the very edge of the sandbox's own memory limit, where Windows inside
83
- it would otherwise start failing, is a build refused memory so that the sandbox stays up.
84
- - **Answers after the fact.** `sandbox doctor` checks your paging file, and `sandbox logs --crash` explains a past
85
- freeze or crash: the gap, blue screens, hardware and memory events, and whether vGPU was on.
86
-
87
- Details and settings: [troubleshooting](docs/troubleshooting.md#the-sandbox-closes-under-heavy-load) and
88
- [configuration](docs/configuration.md#cpu-ram-and-gpu).
73
+ Under load the sandbox slows down instead of failing, and it never takes your PC down with it. Nothing needs setting
74
+ up.
75
+
76
+ - **Sized to fit.** The sandbox gets only the memory your PC can keep in RAM for it, with room left for your PC.
77
+ - **A build budget.** Agents see the CPUs and memory they may really use. Each session gets a matching number of build
78
+ jobs, written to `run\budget.json` for agents to plan with.
79
+ - **Slows down in steps.** As memory fills, build programs get lower priority, then less CPU, then compilers take
80
+ turns. Builds get slower, but nothing is killed, and agents, shells and Windows are never touched.
81
+ - **Your PC has a say.** A watchdog on your PC asks the sandbox to ease off when your PC runs short of memory, CPU or
82
+ disk.
83
+ - **A last resort.** Only at the very edge of the sandbox's memory limit is a build refused memory, so the sandbox
84
+ stays up.
85
+ - **Answers afterwards.** `sandbox doctor` checks your paging file. `sandbox logs --crash` explains a past freeze or
86
+ crash.
87
+
88
+ Details: [heavy load](docs/troubleshooting.md#the-sandbox-closes-under-heavy-load) and
89
+ [CPU, RAM and GPU settings](docs/configuration.md#cpu-ram-and-gpu).
89
90
 
90
91
  ## Commands
91
92
 
92
- | Command | |
93
- |---|---|
94
- | `sandbox` | the menu, a full-screen app with a left navigation: start agents, attach to sessions, pick apps, edit every setting (yours and the project's), all commands, with search |
95
- | `sandbox <agent>`, `claude-sandbox` | start an agent; `-t` for this terminal, `--headless` for no window |
96
- | `sandbox start` | the sandbox without an agent |
97
- | `sandbox attach` / `sessions` / `status` | work with a running sandbox (this folder's project first) |
98
- | `sandbox shell` / `close <id>` | open PowerShell (or cmd) in a project as a session you can attach to; end a session |
99
- | `sandbox restart` / `resume` | restart the agents in place; reopen the last sessions |
100
- | `sandbox projects` | the projects a sandbox can open without a restart: roots, `all`, exclude |
101
- | `sandbox db [start\|stop <name>]` | list, start or stop databases (`sbx-db` inside) |
102
- | `sandbox exec -- <cmd>` | run a command inside |
103
- | `sandbox config get\|set\|reset\|list` | read and change any setting from the command line (`export` / `import` to share them) |
104
- | `sandbox account` | save, switch and rename agent logins |
105
- | `sandbox github` / `vpn` | the GitHub token for sandboxes; the VPN login and status |
106
- | `sandbox web` | (Beta) the web UI: start, stop, status, open |
107
- | `sandbox stop` / `hide` / `show` | shut down, hide or show the window |
108
- | `sandbox data` / `storage` | what's stored and how big, freeing space, moving the data folder |
109
- | `sandbox setup` / `doctor` / `repair` | check this PC, see what will be installed, fix common problems |
110
- | `sandbox engine` | the engines and what each can do on this PC; `engine clean` stops HCS systems left running |
111
- | `sandbox logs [-f] [--crash]` | the sandbox log, or the report of the last crash |
112
- | `sandbox update [--rollback]` / `--version` | update (or go back one version); the installed version |
113
-
114
- All commands and options: [docs/commands.md](docs/commands.md)
93
+ | Command | |
94
+ | ---------------------------------------- | --------------------------------------------------------------------------------- |
95
+ | `sandbox` | the menu: start agents, attach to sessions, pick apps, change any setting, search |
96
+ | `sandbox <agent>`, `claude-sandbox` | start an agent; `-t` for this terminal, `--headless` for no window |
97
+ | `sandbox start` | the sandbox without an agent |
98
+ | `sandbox attach` / `sessions` / `status` | work with a running sandbox (this folder's project first) |
99
+ | `sandbox shell` / `close <id>` | open PowerShell or cmd in a project as a session; end a session |
100
+ | `sandbox restart` / `resume` | restart the agents in place; reopen the last sessions |
101
+ | `sandbox projects` | which projects a sandbox can open without a restart |
102
+ | `sandbox db [start\|stop <name>]` | list, start or stop databases (`sbx-db` inside) |
103
+ | `sandbox exec -- <cmd>` | run a command inside |
104
+ | `sandbox config get\|set\|reset\|list` | read and change settings (`export` / `import` to share them) |
105
+ | `sandbox account` | save, switch and rename agent logins |
106
+ | `sandbox github` / `vpn` | the GitHub token for sandboxes; the VPN login and status |
107
+ | `sandbox web` | (Beta) the web UI: start, stop, status, open |
108
+ | `sandbox stop` / `hide` / `show` | shut down; hide or show the window |
109
+ | `sandbox data` / `storage` | what is stored and how big; free space; move the data folder |
110
+ | `sandbox setup` / `doctor` / `repair` | check this PC, see what will be installed, fix common problems |
111
+ | `sandbox engine` | (Alpha) the engines and what each can do on this PC |
112
+ | `sandbox logs [-f] [--crash]` | the sandbox log, or the report of the last crash |
113
+ | `sandbox update [--rollback]` | update, or go back one version (`--version` shows the installed one) |
114
+
115
+ Every command and option: [docs/commands.md](docs/commands.md).
115
116
 
116
117
  ## Beta and alpha features
117
118
 
118
- These are off until you turn them on, and one setting turns each off again. Windows Sandbox stays the default and
119
- keeps every feature it has.
119
+ These are off until you turn them on, and one setting turns each off again. Windows Sandbox stays the default engine
120
+ and keeps all its features.
120
121
 
121
- | Feature | Status | |
122
- |---|---|---|
123
- | **Web UI** (`sandbox web`, `web.enabled`) | Beta | Agents, sessions with live terminals, the sandbox's status, apps, accounts and every setting in your browser, with search (Ctrl+K) and a folder picker; on this PC only (loopback, signed in with a token). `web.openOnLaunch` opens it with every sandbox. [web-ui.md](docs/web-ui.md) |
124
- | **Agent commands** (`sandbox agent-commands on`) | Beta | Typing `claude`, `codex` ... in any folder starts it in a hidden sandbox and attaches your terminal |
125
- | **Contained storage** (`sandbox storage contained on`) | Beta | Tools, logins and logs in one disk image per data set, mounted only while a sandbox runs. One admin prompt per launch. [engines](docs/design/engines.md) |
126
- | **VPN** (`sandbox vpn`, `vpn.enabled`) | Alpha | The sandbox's traffic through NordVPN, your own OpenVPN profile or a WireGuard config, with a kill switch that is checked with a real connection. The first real try fixed the install and the kill switch; a tunnel carrying traffic is not confirmed yet: read [vpn.md](docs/vpn.md) first |
127
- | **HCS engine** (`sandbox.engine: hcs`, `sandbox engine`) | Alpha | Headless agents in a Hyper-V isolated Server Core container. `sandbox engine check hcs` shows what your PC lacks; starting it is not enabled yet. Its create, start and stop steps pass on GitHub's Windows Server 2022 and 2025 runners |
122
+ | Feature | Status | What it does |
123
+ | ------------------------------------------------------ | ------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
124
+ | **Web UI** (`sandbox web`, `web.enabled`) | Beta | Agents, live terminals, status, apps, accounts and settings in your browser, with search (Ctrl+K). This PC only, signed in with a token; devices on your network if you allow them. [web-ui.md](docs/web-ui.md) |
125
+ | **Agent commands** (`sandbox agent-commands on`) | Beta | Typing `claude`, `codex` ... in any folder starts that agent in a hidden sandbox and attaches your terminal. |
126
+ | **Contained storage** (`sandbox storage contained on`) | Beta | Tools, logins and logs in one disk image, mounted only while a sandbox runs. One admin prompt per launch. [Details](docs/configuration.md#contained-storage-beta) |
127
+ | **VPN** (`sandbox vpn`, `vpn.enabled`) | Alpha | The sandbox's traffic through NordVPN, your own OpenVPN profile or a WireGuard config, with a kill switch. A tunnel carrying traffic is not confirmed yet: read [vpn.md](docs/vpn.md) first. |
128
+ | **HCS engine** (`sandbox.engine: hcs`) | Alpha | Headless agents in a Hyper-V isolated Server Core container. `sandbox engine check hcs` shows what your PC lacks. Starting it is not enabled yet. |
128
129
 
129
130
  ## Known gaps
130
131
 
131
- - Adding a folder to a RUNNING sandbox needs Windows 11 24H2+ with the updated Windows Sandbox (`wsb share`,
132
- untested). On older Windows, folders inside a project root open at once and anything else offers a restart.
133
- [Details, and how to get `wsb`](docs/projects.md#adding-folders-to-a-running-sandbox-wsb-share). A way for older
134
- Windows through HCS is designed and waiting for a test on a real PC ([design](docs/design/hcs-live-folders.md)).
135
- - Windows Sandbox runs one sandbox at a time per PC; every project and agent shares it.
132
+ - Adding a folder to a **running** sandbox needs Windows 11 24H2+ with the updated Windows Sandbox (`wsb share`,
133
+ untested). On older Windows, folders inside a project root open at once, and anything else offers a restart.
134
+ [Details](docs/projects.md#adding-a-project-to-a-running-sandbox).
135
+ - Windows Sandbox runs one sandbox per PC. Every project and agent shares it.
136
136
  - What is planned next: [roadmap](docs/roadmap.md).
137
137
 
138
138
  ## Documentation
139
139
 
140
- All docs, with one line each: [docs/README.md](docs/README.md). The main ones:
140
+ All docs, one line each: [docs/README.md](docs/README.md). The main ones:
141
141
 
142
- - [Install](docs/install.md): requirements, other ways to install, upgrading, rolling back
143
- - [Commands](docs/commands.md): every command and option, the menu, sessions and attaching
144
- - [Tools and databases](docs/toolchains.md): languages, package managers, databases, agents, what is tested
142
+ - [Install](docs/install.md): requirements, other ways to install, updating, uninstalling
143
+ - [Commands](docs/commands.md): every command and option, the menu, sessions
144
+ - [Tools and databases](docs/toolchains.md): languages, apps, databases, agents
145
145
  - [Configuration](docs/configuration.md): settings, project files, paths, accounts, hooks
146
- - [Several projects](docs/projects.md): project roots, adding a project to a running sandbox, what each agent can see
146
+ - [Several projects](docs/projects.md): project roots, joining a running sandbox, what each agent can see
147
147
  - [Security](docs/security.md): how your PC is protected, secrets, git access
148
148
  - [Web UI](docs/web-ui.md) (Beta) and [VPN](docs/vpn.md) (Alpha)
149
- - [Troubleshooting](docs/troubleshooting.md): common problems, freezes and crash reports
150
- - [Changelog](CHANGELOG.md) and [roadmap](docs/roadmap.md): what shipped, what is next
149
+ - [Troubleshooting](docs/troubleshooting.md): common problems, heavy load, crash reports
150
+ - [Changelog](CHANGELOG.md) and [roadmap](docs/roadmap.md)
151
151
  - [Development](docs/development.md): building, testing, releasing (code layout in [CLAUDE.md](CLAUDE.md))
@@ -118,6 +118,12 @@
118
118
  "msvcVersion": "latest",
119
119
  "sdkVersion": "latest"
120
120
  },
121
+ "unreal": {
122
+ "enabled": "auto",
123
+ "acceptLicense": false,
124
+ "components": [],
125
+ "keepInstallFiles": true
126
+ },
121
127
  "cpp": {
122
128
  "enabled": "auto",
123
129
  "flexBison": true
@@ -14,7 +14,7 @@ import { ConfigFile } from '../settings/index.js';
14
14
  import { accessStatus, allowDevice, lanOff, lanOn, revokeAccess, revokeAllAccess } from './access.def.js';
15
15
  /** The access list of this user (the folder is the web state's private one). */
16
16
  export function accessStoreOf(ctx) {
17
- return AccessStore.at(ctx.storageRoot, SecretStore.standard(), {
17
+ return AccessStore.at(ctx.storageRoot, SecretStore.standard(ctx.storageRoot), {
18
18
  // The self-test never changes folder permissions; its storage is a temp folder.
19
19
  protect: selfTestRunning() ? undefined : (dir) => protectPrivateFolder(dir),
20
20
  });
@@ -2,8 +2,8 @@
2
2
  import { createRequire as __createRequire } from 'node:module'; const require = __createRequire(import.meta.url);
3
3
  import {
4
4
  run
5
- } from "./chunk-7EXDUNE7.js";
6
- import "./chunk-HIC4CUMY.js";
5
+ } from "./chunk-QLGGAG3D.js";
6
+ import "./chunk-REE3EMHD.js";
7
7
 
8
8
  // src/bin/agent-sandbox.ts
9
9
  run(process.argv.slice(2));
@@ -226,7 +226,7 @@ import {
226
226
  withOperationCommands,
227
227
  working,
228
228
  writeJson
229
- } from "./chunk-HIC4CUMY.js";
229
+ } from "./chunk-REE3EMHD.js";
230
230
 
231
231
  // node_modules/commander/lib/error.js
232
232
  var require_error = __commonJS({
@@ -25938,6 +25938,7 @@ var DEFAULTS = {
25938
25938
  linkSlots: "auto"
25939
25939
  },
25940
25940
  msvc: { enabled: "auto", acceptLicense: false, msvcVersion: "latest", sdkVersion: "latest" },
25941
+ unreal: { enabled: "auto", acceptLicense: false, components: [], keepInstallFiles: true },
25941
25942
  cpp: { enabled: "auto", flexBison: true },
25942
25943
  dotnet: {
25943
25944
  enabled: "auto",
@@ -46053,7 +46054,7 @@ var SandboxSchema = external_exports.strictObject({
46053
46054
  "When the sandbox (or this PC) runs low on memory, slow builds down in steps, like a PC that gets slower instead of failing: build programs get lower CPU and memory priority, then less CPU, then compilers take turns (the waiting ones briefly suspended and trimmed to the paging file). Nothing is stopped or killed, and the agents themselves are never touched. Yours only: a project file cannot change it."
46054
46055
  ),
46055
46056
  vGpu: external_exports.boolean().describe(
46056
- "Virtual GPU. Off by default: Microsoft notes it widens the sandbox attack surface. The sandbox then uses this PC's graphics card, and with some graphics drivers heavy use can freeze the whole PC: turn it on only when a program in the sandbox needs the GPU (the mesa toolchain gives software OpenGL without it)."
46057
+ "Virtual GPU. Off by default: Microsoft notes it widens the sandbox attack surface. The sandbox then uses this PC's graphics card, and with some graphics drivers heavy use can freeze the whole PC: turn it on only when a program in the sandbox needs the GPU (the mesa toolchain gives software OpenGL without it). Browsers in the sandbox never use it (they draw in software)."
46057
46058
  ),
46058
46059
  networking: external_exports.boolean().describe("Internet access. false is the only hard network isolation Windows Sandbox offers."),
46059
46060
  clipboard: external_exports.boolean().describe(
@@ -46215,6 +46216,21 @@ var ToolchainsSchema = external_exports.strictObject({
46215
46216
  msvcVersion: external_exports.string().min(1).describe('"latest" or an MSVC tools version prefix, e.g. "14.44".'),
46216
46217
  sdkVersion: external_exports.string().min(1).describe('"latest" or a Windows SDK build, e.g. "26100" or "10.0.22621".')
46217
46218
  }),
46219
+ unreal: external_exports.strictObject({
46220
+ enabled: enabled(
46221
+ "Unreal Engine development: Visual Studio Community 2022 with the C++ game workload (MSVC, a Windows 11 SDK, .NET Framework targeting packs, Unreal integration and the Epic Games Launcher) and the DirectX End-User Runtime. A real installer: it runs every boot (~10 GB on the sandbox disk). The engine itself comes from the Epic Games Launcher or its source.",
46222
+ "a .uproject or .uplugin"
46223
+ ),
46224
+ acceptLicense: external_exports.boolean().describe(
46225
+ "Required to install: you accept the Visual Studio Community licence terms (https://visualstudio.microsoft.com/license-terms/) and the DirectX End-User Runtime licence."
46226
+ ),
46227
+ components: StringsSchema.describe(
46228
+ 'More Visual Studio workload or component IDs to add, e.g. ["Microsoft.VisualStudio.Component.VC.Llvm.Clang"].'
46229
+ ),
46230
+ keepInstallFiles: external_exports.boolean().describe(
46231
+ "Keep an offline copy of the Visual Studio install files in tools\\visualstudio (~10 GB, made once), so later boots install without downloading them again. Skipped while that disk has too little room."
46232
+ )
46233
+ }),
46218
46234
  cpp: external_exports.strictObject({
46219
46235
  enabled: enabled(
46220
46236
  "MinGW-w64 GCC with CMake, Ninja, premake5 and mingw32-make (also Rust's linker).",
@@ -54689,7 +54705,23 @@ import { spawn as spawn8 } from "node:child_process";
54689
54705
  // src/host/secrets/secret-store.ts
54690
54706
  import { spawnSync as spawnSync19 } from "node:child_process";
54691
54707
  var TIMEOUT_MS2 = 6e4;
54708
+ var toolsFor = /* @__PURE__ */ new Map();
54709
+ function dpapiTool(storageRoot) {
54710
+ if (!toolsFor.has(storageRoot)) {
54711
+ let exe = null;
54712
+ try {
54713
+ exe = hostToolsExe(storageRoot);
54714
+ } catch {
54715
+ }
54716
+ toolsFor.set(storageRoot, exe);
54717
+ }
54718
+ return toolsFor.get(storageRoot) ?? null;
54719
+ }
54692
54720
  var DpapiBox = class {
54721
+ constructor(storageRoot) {
54722
+ this.storageRoot = storageRoot;
54723
+ }
54724
+ storageRoot;
54693
54725
  kind = "dpapi1";
54694
54726
  seal(plain2) {
54695
54727
  return this.run("protect", plain2.toString("base64"));
@@ -54698,7 +54730,9 @@ var DpapiBox = class {
54698
54730
  return Buffer.from(this.run("unprotect", sealed), "base64");
54699
54731
  }
54700
54732
  run(mode, input2) {
54701
- const result = spawnSync19(SYSTEM.powershell(), nativeScript("protect-data.ps1", ["-Mode", mode]), {
54733
+ const tools = this.storageRoot ? dpapiTool(this.storageRoot) : null;
54734
+ const [exe, args] = tools ? [tools, [mode]] : [SYSTEM.powershell(), nativeScript("protect-data.ps1", ["-Mode", mode])];
54735
+ const result = spawnSync19(exe, args, {
54702
54736
  input: input2,
54703
54737
  encoding: "utf8",
54704
54738
  windowsHide: true,
@@ -54726,17 +54760,17 @@ var SecretStore = class _SecretStore {
54726
54760
  this.box = box;
54727
54761
  }
54728
54762
  box;
54729
- /** Windows DPAPI, current user. */
54730
- static dpapi() {
54731
- return new _SecretStore(new DpapiBox());
54763
+ /** Windows DPAPI, current user; with a storage folder, through its HostTools.exe (much faster than PowerShell). */
54764
+ static dpapi(storageRoot = null) {
54765
+ return new _SecretStore(new DpapiBox(storageRoot));
54732
54766
  }
54733
54767
  /** The test stand-in (not secure). */
54734
54768
  static memory() {
54735
54769
  return new _SecretStore(new MemoryBox());
54736
54770
  }
54737
54771
  /** What the program uses: DPAPI, except during the self-test (it never spawns Windows for this). */
54738
- static standard() {
54739
- return selfTestRunning() ? _SecretStore.memory() : _SecretStore.dpapi();
54772
+ static standard(storageRoot = null) {
54773
+ return selfTestRunning() ? _SecretStore.memory() : _SecretStore.dpapi(storageRoot);
54740
54774
  }
54741
54775
  /** True when `value` looks like something seal() made (any box). */
54742
54776
  static isSealed(value) {
@@ -55134,7 +55168,7 @@ function realLiveFolders(storageRoot, dataPath) {
55134
55168
  return new LiveFolders({
55135
55169
  storageRoot,
55136
55170
  dataPath,
55137
- secrets: SecretStore.standard(),
55171
+ secrets: SecretStore.standard(storageRoot),
55138
55172
  elevated: new ScriptLivePort(),
55139
55173
  userSid: currentUserSid,
55140
55174
  isAlive: isSandboxRunning
@@ -56008,6 +56042,8 @@ var MAX_PLUGIN_BYTES = 1024 * 1024 * 1024;
56008
56042
  var MAX_SETTINGS_BYTES = 4 * 1024 * 1024;
56009
56043
  var MAX_DEPTH = 24;
56010
56044
  var INSTALLED = "installed_plugins.json";
56045
+ var RECORDS = [INSTALLED, "known_marketplaces.json"];
56046
+ var MAX_RECORD_BYTES2 = 4 * 1024 * 1024;
56011
56047
  function isObject2(value) {
56012
56048
  return typeof value === "object" && value !== null && !Array.isArray(value);
56013
56049
  }
@@ -56054,7 +56090,7 @@ var PluginShare = class _PluginShare {
56054
56090
  /** When a sandbox ends: its plugins refresh the shared set. Never throws; returns the problem, if any. */
56055
56091
  saveQuietly(dataPath, claudeDir) {
56056
56092
  try {
56057
- if (_PluginShare.hasPlugins(claudeDir)) this.save(dataPath, claudeDir);
56093
+ if (_PluginShare.hasPlugins(claudeDir) && !this.matches(claudeDir)) this.save(dataPath, claudeDir);
56058
56094
  return null;
56059
56095
  } catch (e) {
56060
56096
  return errMsg(e);
@@ -56108,9 +56144,24 @@ var PluginShare = class _PluginShare {
56108
56144
  if (isObject2(shared[key3])) merged[key3] = { ...shared[key3], ...isObject2(merged[key3]) ? merged[key3] : {} };
56109
56145
  writeSandboxJson(file2, merged);
56110
56146
  }
56147
+ /**
56148
+ * Whether the shared set already holds this Claude folder's plugins: the same plugin records and plugin settings.
56149
+ * Copying a big plugins folder takes seconds, so a switch between accounts with the same plugins skips it.
56150
+ */
56151
+ matches(claudeDir) {
56152
+ if (!this.hasShared()) return false;
56153
+ const same3 = (a, b) => JSON.stringify(a) === JSON.stringify(b);
56154
+ for (const name2 of RECORDS) {
56155
+ const own2 = readUntrusted(path67.join(claudeDir, "plugins", name2), MAX_RECORD_BYTES2);
56156
+ if (!same3(own2, readUntrusted(path67.join(this.pluginsDir, name2), MAX_RECORD_BYTES2))) return false;
56157
+ }
56158
+ const shared = readUntrusted(this.settingsFile, MAX_SETTINGS_BYTES);
56159
+ return same3(pluginSettings(claudeDir), isObject2(shared) ? shared : {});
56160
+ }
56111
56161
  /** One step when an account is switched to. */
56112
56162
  sync(dataPath, claudeDir) {
56113
56163
  if (_PluginShare.hasPlugins(claudeDir)) {
56164
+ if (this.matches(claudeDir)) return "nothing";
56114
56165
  this.save(dataPath, claudeDir);
56115
56166
  return "saved";
56116
56167
  }
@@ -56170,7 +56221,7 @@ function assertName(name2) {
56170
56221
  }
56171
56222
  var AccountStore = class {
56172
56223
  /** @param sharePlugins claudeProfile.sharePluginsAcrossAccounts: carry Claude plugins to the account switched to */
56173
- constructor(storageRoot, sharePlugins = false, secrets = SecretStore.standard()) {
56224
+ constructor(storageRoot, sharePlugins = false, secrets = SecretStore.standard(storageRoot)) {
56174
56225
  this.storageRoot = storageRoot;
56175
56226
  this.sharePlugins = sharePlugins;
56176
56227
  this.secrets = secrets;
@@ -56345,7 +56396,7 @@ var AgentAccountStore = class {
56345
56396
  /**
56346
56397
  * @param loginFiles files of the login, relative to the folder they are read from and written to
56347
56398
  */
56348
- constructor(storageRoot, agent, loginFiles, secrets = SecretStore.standard()) {
56399
+ constructor(storageRoot, agent, loginFiles, secrets = SecretStore.standard(storageRoot)) {
56349
56400
  this.storageRoot = storageRoot;
56350
56401
  this.agent = agent;
56351
56402
  this.loginFiles = loginFiles;
@@ -56508,7 +56559,7 @@ function checkGithubToken(token) {
56508
56559
  return githubTokenKind(token) ?? fail("That is not a GitHub personal access token.", "Run: sandbox github login");
56509
56560
  }
56510
56561
  var GithubToken = class {
56511
- constructor(storageRoot, secrets = SecretStore.standard()) {
56562
+ constructor(storageRoot, secrets = SecretStore.standard(storageRoot)) {
56512
56563
  this.storageRoot = storageRoot;
56513
56564
  this.secrets = secrets;
56514
56565
  }
@@ -57191,6 +57242,7 @@ var MARKERS = {
57191
57242
  ],
57192
57243
  rust: ["Cargo.toml", "rust-toolchain", "rust-toolchain.toml"],
57193
57244
  msvc: ["*.vcxproj", "CMakePresets.json", "CMakeUserPresets.json"],
57245
+ unreal: ["*.uproject", "*.uplugin"],
57194
57246
  cpp: [
57195
57247
  "CMakeLists.txt",
57196
57248
  "Makefile",
@@ -57249,6 +57301,11 @@ function decideToolchains(settings, entries, pcHas, hints = {}) {
57249
57301
  on: false,
57250
57302
  reason: "would be used (" + result.msvc.reason + "); set toolchains.msvc.acceptLicense to install it"
57251
57303
  };
57304
+ if (settings.unreal.enabled === "auto" && result.unreal.on && !settings.unreal.acceptLicense)
57305
+ result.unreal = {
57306
+ on: false,
57307
+ reason: "would be used (" + result.unreal.reason + "); set toolchains.unreal.acceptLicense to install it"
57308
+ };
57252
57309
  if (result.rust.on && !result.msvc.on && !result.cpp.on && settings.cpp.enabled !== false)
57253
57310
  result.cpp = { on: true, reason: "the linker for Rust" };
57254
57311
  if (result.python.on && settings.uv.enabled === "auto" && settings.python.tools.length > 0 && !result.uv.on)
@@ -59144,7 +59201,7 @@ function loginProblem(c2) {
59144
59201
  return null;
59145
59202
  }
59146
59203
  var VpnLogin = class {
59147
- constructor(storageRoot, secrets = SecretStore.standard()) {
59204
+ constructor(storageRoot, secrets = SecretStore.standard(storageRoot)) {
59148
59205
  this.storageRoot = storageRoot;
59149
59206
  this.secrets = secrets;
59150
59207
  }
@@ -70288,7 +70345,7 @@ var TlsStore = class {
70288
70345
 
70289
70346
  // src/app/features/access/access.run.ts
70290
70347
  function accessStoreOf(ctx) {
70291
- return AccessStore.at(ctx.storageRoot, SecretStore.standard(), {
70348
+ return AccessStore.at(ctx.storageRoot, SecretStore.standard(ctx.storageRoot), {
70292
70349
  // The self-test never changes folder permissions; its storage is a temp folder.
70293
70350
  protect: selfTestRunning() ? void 0 : (dir) => protectPrivateFolder(dir)
70294
70351
  });
@@ -78297,7 +78354,7 @@ async function attachOpened(ctx, session) {
78297
78354
  nextStep("sandbox attach " + session);
78298
78355
  return 0;
78299
78356
  }
78300
- const { attach: attach2 } = await import("./chunk-PXTLKIV4.js");
78357
+ const { attach: attach2 } = await import("./chunk-XYUVIVJT.js");
78301
78358
  return attach2({ ...ctx, options: { ...ctx.options, positionals: [session] } });
78302
78359
  }
78303
78360
  function definitionHandler(def) {
@@ -78389,7 +78446,7 @@ function remoteAudit(ctx) {
78389
78446
  };
78390
78447
  }
78391
78448
  function remoteGate(ctx) {
78392
- const secrets = SecretStore.standard();
78449
+ const secrets = SecretStore.standard(ctx.storageRoot);
78393
78450
  let ownerSid = "";
78394
78451
  try {
78395
78452
  ownerSid = currentUserSid();
@@ -1,7 +1,7 @@
1
1
  import { createRequire as __createRequire } from 'node:module'; const require = __createRequire(import.meta.url);
2
2
  import {
3
3
  attach
4
- } from "./chunk-HIC4CUMY.js";
4
+ } from "./chunk-REE3EMHD.js";
5
5
  export {
6
6
  attach
7
7
  };
@@ -2,8 +2,8 @@
2
2
  import { createRequire as __createRequire } from 'node:module'; const require = __createRequire(import.meta.url);
3
3
  import {
4
4
  run
5
- } from "./chunk-7EXDUNE7.js";
6
- import "./chunk-HIC4CUMY.js";
5
+ } from "./chunk-QLGGAG3D.js";
6
+ import "./chunk-REE3EMHD.js";
7
7
 
8
8
  // src/bin/claude-host.ts
9
9
  var args = process.argv.slice(2);
@@ -2,8 +2,8 @@
2
2
  import { createRequire as __createRequire } from 'node:module'; const require = __createRequire(import.meta.url);
3
3
  import {
4
4
  run
5
- } from "./chunk-7EXDUNE7.js";
6
- import "./chunk-HIC4CUMY.js";
5
+ } from "./chunk-QLGGAG3D.js";
6
+ import "./chunk-REE3EMHD.js";
7
7
 
8
8
  // src/bin/claude-sbx.ts
9
9
  run(process.argv.slice(2), { harness: "claude" });
@@ -2,8 +2,8 @@
2
2
  import { createRequire as __createRequire } from 'node:module'; const require = __createRequire(import.meta.url);
3
3
  import {
4
4
  run
5
- } from "./chunk-7EXDUNE7.js";
6
- import "./chunk-HIC4CUMY.js";
5
+ } from "./chunk-QLGGAG3D.js";
6
+ import "./chunk-REE3EMHD.js";
7
7
 
8
8
  // src/bin/codex-sbx.ts
9
9
  run(process.argv.slice(2), { harness: "codex" });
@@ -2,8 +2,8 @@
2
2
  import { createRequire as __createRequire } from 'node:module'; const require = __createRequire(import.meta.url);
3
3
  import {
4
4
  run
5
- } from "./chunk-7EXDUNE7.js";
6
- import "./chunk-HIC4CUMY.js";
5
+ } from "./chunk-QLGGAG3D.js";
6
+ import "./chunk-REE3EMHD.js";
7
7
 
8
8
  // src/bin/gemini-sbx.ts
9
9
  run(process.argv.slice(2), { harness: "gemini" });
@@ -2,8 +2,8 @@
2
2
  import { createRequire as __createRequire } from 'node:module'; const require = __createRequire(import.meta.url);
3
3
  import {
4
4
  run
5
- } from "./chunk-7EXDUNE7.js";
6
- import "./chunk-HIC4CUMY.js";
5
+ } from "./chunk-QLGGAG3D.js";
6
+ import "./chunk-REE3EMHD.js";
7
7
 
8
8
  // src/bin/sandbox.ts
9
9
  run(process.argv.slice(2));
@@ -2,8 +2,8 @@
2
2
  import { createRequire as __createRequire } from 'node:module'; const require = __createRequire(import.meta.url);
3
3
  import {
4
4
  run
5
- } from "./chunk-7EXDUNE7.js";
6
- import "./chunk-HIC4CUMY.js";
5
+ } from "./chunk-QLGGAG3D.js";
6
+ import "./chunk-REE3EMHD.js";
7
7
 
8
8
  // src/bin/sbx-hide.ts
9
9
  run(process.argv.slice(2), { command: "hide" });