windows-development-sandbox 0.0.0-stage → 1.1.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.
- package/.sandbox-config.example.json +14 -0
- package/LICENSE +21 -0
- package/README.md +94 -2
- package/config.example.json +349 -0
- package/dist/api.d.ts +31 -0
- package/dist/api.js +31 -0
- package/dist/bin/agent-sandbox.d.ts +2 -0
- package/dist/bin/agent-sandbox.js +3 -0
- package/dist/bin/claude-host.d.ts +2 -0
- package/dist/bin/claude-host.js +5 -0
- package/dist/bin/claude-sbx.d.ts +2 -0
- package/dist/bin/claude-sbx.js +3 -0
- package/dist/bin/codex-sbx.d.ts +2 -0
- package/dist/bin/codex-sbx.js +3 -0
- package/dist/bin/gemini-sbx.d.ts +2 -0
- package/dist/bin/gemini-sbx.js +3 -0
- package/dist/bin/sandbox.d.ts +2 -0
- package/dist/bin/sandbox.js +4 -0
- package/dist/bin/sbx-hide.d.ts +2 -0
- package/dist/bin/sbx-hide.js +3 -0
- package/dist/bin/sbx-show.d.ts +2 -0
- package/dist/bin/sbx-show.js +3 -0
- package/dist/cli/args.d.ts +52 -0
- package/dist/cli/args.js +143 -0
- package/dist/cli/colors.d.ts +24 -0
- package/dist/cli/colors.js +42 -0
- package/dist/cli/commands/accounts.d.ts +2 -0
- package/dist/cli/commands/accounts.js +52 -0
- package/dist/cli/commands/agent-commands.d.ts +6 -0
- package/dist/cli/commands/agent-commands.js +61 -0
- package/dist/cli/commands/context.d.ts +23 -0
- package/dist/cli/commands/context.js +57 -0
- package/dist/cli/commands/data/clean.d.ts +15 -0
- package/dist/cli/commands/data/clean.js +101 -0
- package/dist/cli/commands/data/collect.d.ts +11 -0
- package/dist/cli/commands/data/collect.js +54 -0
- package/dist/cli/commands/data/index.d.ts +4 -0
- package/dist/cli/commands/data/index.js +45 -0
- package/dist/cli/commands/data/remove.d.ts +2 -0
- package/dist/cli/commands/data/remove.js +30 -0
- package/dist/cli/commands/index.d.ts +10 -0
- package/dist/cli/commands/index.js +10 -0
- package/dist/cli/commands/launch.d.ts +29 -0
- package/dist/cli/commands/launch.js +333 -0
- package/dist/cli/commands/maintenance.d.ts +8 -0
- package/dist/cli/commands/maintenance.js +154 -0
- package/dist/cli/commands/project.d.ts +29 -0
- package/dist/cli/commands/project.js +63 -0
- package/dist/cli/commands/projects.d.ts +14 -0
- package/dist/cli/commands/projects.js +146 -0
- package/dist/cli/commands/repair/checks.d.ts +2 -0
- package/dist/cli/commands/repair/checks.js +170 -0
- package/dist/cli/commands/repair/finders.d.ts +30 -0
- package/dist/cli/commands/repair/finders.js +108 -0
- package/dist/cli/commands/repair/index.d.ts +12 -0
- package/dist/cli/commands/repair/index.js +61 -0
- package/dist/cli/commands/repair/types.d.ts +26 -0
- package/dist/cli/commands/repair/types.js +3 -0
- package/dist/cli/commands/restart.d.ts +6 -0
- package/dist/cli/commands/restart.js +85 -0
- package/dist/cli/commands/sessions.d.ts +12 -0
- package/dist/cli/commands/sessions.js +257 -0
- package/dist/cli/commands/setup/checks.d.ts +13 -0
- package/dist/cli/commands/setup/checks.js +71 -0
- package/dist/cli/commands/setup/facts.d.ts +31 -0
- package/dist/cli/commands/setup/facts.js +60 -0
- package/dist/cli/commands/setup/index.d.ts +2 -0
- package/dist/cli/commands/setup/index.js +43 -0
- package/dist/cli/commands/user-config.d.ts +8 -0
- package/dist/cli/commands/user-config.js +41 -0
- package/dist/cli/history.d.ts +11 -0
- package/dist/cli/history.js +21 -0
- package/dist/cli/index.d.ts +20 -0
- package/dist/cli/index.js +121 -0
- package/dist/cli/manifest.d.ts +103 -0
- package/dist/cli/manifest.js +107 -0
- package/dist/cli/menu-multi.d.ts +12 -0
- package/dist/cli/menu-multi.js +82 -0
- package/dist/cli/menu.d.ts +14 -0
- package/dist/cli/menu.js +290 -0
- package/dist/cli/progress.d.ts +9 -0
- package/dist/cli/progress.js +49 -0
- package/dist/cli/settings/edit.d.ts +13 -0
- package/dist/cli/settings/edit.js +19 -0
- package/dist/cli/settings/index.d.ts +8 -0
- package/dist/cli/settings/index.js +131 -0
- package/dist/cli/settings/prompts.d.ts +7 -0
- package/dist/cli/settings/prompts.js +48 -0
- package/dist/cli/settings/schema.d.ts +33 -0
- package/dist/cli/settings/schema.js +29 -0
- package/dist/cli/validate.d.ts +17 -0
- package/dist/cli/validate.js +89 -0
- package/dist/core/config.d.ts +17 -0
- package/dist/core/config.js +106 -0
- package/dist/core/detect-databases.d.ts +15 -0
- package/dist/core/detect-databases.js +147 -0
- package/dist/core/detect-pwsh.d.ts +18 -0
- package/dist/core/detect-pwsh.js +111 -0
- package/dist/core/detect-toolchains.d.ts +30 -0
- package/dist/core/detect-toolchains.js +58 -0
- package/dist/core/disk.d.ts +16 -0
- package/dist/core/disk.js +55 -0
- package/dist/core/local-config.d.ts +20 -0
- package/dist/core/local-config.js +77 -0
- package/dist/core/project-policy.d.ts +15 -0
- package/dist/core/project-policy.js +35 -0
- package/dist/core/prompt.d.ts +4 -0
- package/dist/core/prompt.js +15 -0
- package/dist/core/safe-paths.d.ts +4 -0
- package/dist/core/safe-paths.js +37 -0
- package/dist/core/schema/common.d.ts +17 -0
- package/dist/core/schema/common.js +15 -0
- package/dist/core/schema/config.d.ts +594 -0
- package/dist/core/schema/config.js +63 -0
- package/dist/core/schema/databases.d.ts +33 -0
- package/dist/core/schema/databases.js +35 -0
- package/dist/core/schema/harness.d.ts +12 -0
- package/dist/core/schema/harness.js +17 -0
- package/dist/core/schema/json-schema.d.ts +5 -0
- package/dist/core/schema/json-schema.js +25 -0
- package/dist/core/schema/profile.d.ts +27 -0
- package/dist/core/schema/profile.js +29 -0
- package/dist/core/schema/projects.d.ts +9 -0
- package/dist/core/schema/projects.js +11 -0
- package/dist/core/schema/sandbox.d.ts +50 -0
- package/dist/core/schema/sandbox.js +36 -0
- package/dist/core/schema/toolchains.d.ts +93 -0
- package/dist/core/schema/toolchains.js +83 -0
- package/dist/core/schema.d.ts +6 -0
- package/dist/core/schema.js +8 -0
- package/dist/core/types.d.ts +190 -0
- package/dist/core/types.js +1 -0
- package/dist/core/util.d.ts +60 -0
- package/dist/core/util.js +154 -0
- package/dist/core/workspace.d.ts +18 -0
- package/dist/core/workspace.js +128 -0
- package/dist/guest/boot-env.d.ts +4 -0
- package/dist/guest/boot-env.js +25 -0
- package/dist/guest/cmdline.d.ts +12 -0
- package/dist/guest/cmdline.js +23 -0
- package/dist/guest/daemon/exec.d.ts +5 -0
- package/dist/guest/daemon/exec.js +32 -0
- package/dist/guest/daemon/project.d.ts +14 -0
- package/dist/guest/daemon/project.js +132 -0
- package/dist/guest/daemon/session.d.ts +13 -0
- package/dist/guest/daemon/session.js +139 -0
- package/dist/guest/daemon/shutdown.d.ts +1 -0
- package/dist/guest/daemon/shutdown.js +21 -0
- package/dist/guest/daemon/state.d.ts +17 -0
- package/dist/guest/daemon/state.js +31 -0
- package/dist/guest/daemon.d.ts +1 -0
- package/dist/guest/daemon.js +53 -0
- package/dist/guest/db.d.ts +1 -0
- package/dist/guest/db.js +75 -0
- package/dist/guest/env.d.ts +51 -0
- package/dist/guest/env.js +101 -0
- package/dist/guest/gitguard.d.ts +7 -0
- package/dist/guest/gitguard.js +60 -0
- package/dist/guest/gitrules.d.ts +2 -0
- package/dist/guest/gitrules.js +11 -0
- package/dist/guest/guide.d.ts +16 -0
- package/dist/guest/guide.js +69 -0
- package/dist/guest/helpers.d.ts +3 -0
- package/dist/guest/helpers.js +26 -0
- package/dist/guest/main.d.ts +1 -0
- package/dist/guest/main.js +130 -0
- package/dist/guest/ports.d.ts +6 -0
- package/dist/guest/ports.js +22 -0
- package/dist/guest/project-context.d.ts +7 -0
- package/dist/guest/project-context.js +10 -0
- package/dist/guest/project-env.d.ts +20 -0
- package/dist/guest/project-env.js +20 -0
- package/dist/guest/project-status.d.ts +5 -0
- package/dist/guest/project-status.js +17 -0
- package/dist/guest/ptyhost.d.ts +22 -0
- package/dist/guest/ptyhost.js +36 -0
- package/dist/guest/setup/agents.d.ts +11 -0
- package/dist/guest/setup/agents.js +87 -0
- package/dist/guest/setup/claude.d.ts +21 -0
- package/dist/guest/setup/claude.js +146 -0
- package/dist/guest/setup/environment.d.ts +16 -0
- package/dist/guest/setup/environment.js +69 -0
- package/dist/guest/setup/hooks.d.ts +9 -0
- package/dist/guest/setup/hooks.js +50 -0
- package/dist/guest/setup/network.d.ts +10 -0
- package/dist/guest/setup/network.js +99 -0
- package/dist/guest/setup/policy.d.ts +3 -0
- package/dist/guest/setup/policy.js +18 -0
- package/dist/guest/setup/user.d.ts +7 -0
- package/dist/guest/setup/user.js +47 -0
- package/dist/guest/toolchains/catalogue.d.ts +55 -0
- package/dist/guest/toolchains/catalogue.js +31 -0
- package/dist/guest/toolchains/cli.d.ts +10 -0
- package/dist/guest/toolchains/cli.js +72 -0
- package/dist/guest/toolchains/common.d.ts +54 -0
- package/dist/guest/toolchains/common.js +147 -0
- package/dist/guest/toolchains/databases/dynamodb.d.ts +8 -0
- package/dist/guest/toolchains/databases/dynamodb.js +52 -0
- package/dist/guest/toolchains/databases/index.d.ts +6 -0
- package/dist/guest/toolchains/databases/index.js +62 -0
- package/dist/guest/toolchains/databases/mongodb.d.ts +3 -0
- package/dist/guest/toolchains/databases/mongodb.js +31 -0
- package/dist/guest/toolchains/databases/mysql.d.ts +3 -0
- package/dist/guest/toolchains/databases/mysql.js +38 -0
- package/dist/guest/toolchains/databases/postgres.d.ts +5 -0
- package/dist/guest/toolchains/databases/postgres.js +38 -0
- package/dist/guest/toolchains/databases/redis.d.ts +3 -0
- package/dist/guest/toolchains/databases/redis.js +16 -0
- package/dist/guest/toolchains/databases/server.d.ts +14 -0
- package/dist/guest/toolchains/databases/server.js +52 -0
- package/dist/guest/toolchains/git.d.ts +3 -0
- package/dist/guest/toolchains/git.js +121 -0
- package/dist/guest/toolchains/go.d.ts +3 -0
- package/dist/guest/toolchains/go.js +33 -0
- package/dist/guest/toolchains/index.d.ts +17 -0
- package/dist/guest/toolchains/index.js +80 -0
- package/dist/guest/toolchains/java.d.ts +8 -0
- package/dist/guest/toolchains/java.js +96 -0
- package/dist/guest/toolchains/leftovers.d.ts +2 -0
- package/dist/guest/toolchains/leftovers.js +26 -0
- package/dist/guest/toolchains/managers.d.ts +16 -0
- package/dist/guest/toolchains/managers.js +84 -0
- package/dist/guest/toolchains/native/binstall.d.ts +7 -0
- package/dist/guest/toolchains/native/binstall.js +52 -0
- package/dist/guest/toolchains/native/cpp.d.ts +4 -0
- package/dist/guest/toolchains/native/cpp.js +38 -0
- package/dist/guest/toolchains/native/dotnet.d.ts +4 -0
- package/dist/guest/toolchains/native/dotnet.js +103 -0
- package/dist/guest/toolchains/native/mesa.d.ts +7 -0
- package/dist/guest/toolchains/native/mesa.js +46 -0
- package/dist/guest/toolchains/native/msvc/environment.d.ts +16 -0
- package/dist/guest/toolchains/native/msvc/environment.js +57 -0
- package/dist/guest/toolchains/native/msvc/index.d.ts +6 -0
- package/dist/guest/toolchains/native/msvc/index.js +48 -0
- package/dist/guest/toolchains/native/msvc/packages.d.ts +6 -0
- package/dist/guest/toolchains/native/msvc/packages.js +156 -0
- package/dist/guest/toolchains/native/msvc/tree.d.ts +15 -0
- package/dist/guest/toolchains/native/msvc/tree.js +21 -0
- package/dist/guest/toolchains/native/rust.d.ts +3 -0
- package/dist/guest/toolchains/native/rust.js +45 -0
- package/dist/guest/toolchains/node.d.ts +3 -0
- package/dist/guest/toolchains/node.js +152 -0
- package/dist/guest/toolchains/plan.d.ts +22 -0
- package/dist/guest/toolchains/plan.js +96 -0
- package/dist/guest/toolchains/pwsh.d.ts +4 -0
- package/dist/guest/toolchains/pwsh.js +14 -0
- package/dist/guest/toolchains/python.d.ts +3 -0
- package/dist/guest/toolchains/python.js +54 -0
- package/dist/guest/toolchains/runtimes.d.ts +19 -0
- package/dist/guest/toolchains/runtimes.js +38 -0
- package/dist/guest/toolchains/scripting/php.d.ts +3 -0
- package/dist/guest/toolchains/scripting/php.js +71 -0
- package/dist/guest/toolchains/scripting/ruby.d.ts +3 -0
- package/dist/guest/toolchains/scripting/ruby.js +47 -0
- package/dist/guest/toolchains/scripting/vcruntime.d.ts +7 -0
- package/dist/guest/toolchains/scripting/vcruntime.js +45 -0
- package/dist/guest/toolchains/versions.d.ts +47 -0
- package/dist/guest/toolchains/versions.js +77 -0
- package/dist/guest/toolchains/vscode.d.ts +2 -0
- package/dist/guest/toolchains/vscode.js +53 -0
- package/dist/guest/view.d.ts +1 -0
- package/dist/guest/view.js +42 -0
- package/dist/host/accounts.d.ts +32 -0
- package/dist/host/accounts.js +128 -0
- package/dist/host/agent-commands.d.ts +25 -0
- package/dist/host/agent-commands.js +145 -0
- package/dist/host/attach.d.ts +17 -0
- package/dist/host/attach.js +69 -0
- package/dist/host/channel.d.ts +38 -0
- package/dist/host/channel.js +162 -0
- package/dist/host/claude-profile.d.ts +15 -0
- package/dist/host/claude-profile.js +107 -0
- package/dist/host/cleanup.d.ts +23 -0
- package/dist/host/cleanup.js +57 -0
- package/dist/host/database-plan.d.ts +12 -0
- package/dist/host/database-plan.js +52 -0
- package/dist/host/generate.d.ts +7 -0
- package/dist/host/generate.js +98 -0
- package/dist/host/join.d.ts +28 -0
- package/dist/host/join.js +76 -0
- package/dist/host/launch/mappings.d.ts +3 -0
- package/dist/host/launch/mappings.js +50 -0
- package/dist/host/launch/projects.d.ts +15 -0
- package/dist/host/launch/projects.js +56 -0
- package/dist/host/launch/stage.d.ts +11 -0
- package/dist/host/launch/stage.js +66 -0
- package/dist/host/launch/wsb.d.ts +10 -0
- package/dist/host/launch/wsb.js +34 -0
- package/dist/host/pc-scan.d.ts +6 -0
- package/dist/host/pc-scan.js +37 -0
- package/dist/host/personalize.d.ts +10 -0
- package/dist/host/personalize.js +97 -0
- package/dist/host/platform.d.ts +19 -0
- package/dist/host/platform.js +126 -0
- package/dist/host/project-scan.d.ts +7 -0
- package/dist/host/project-scan.js +89 -0
- package/dist/host/projects.d.ts +100 -0
- package/dist/host/projects.js +147 -0
- package/dist/host/repo-guard.d.ts +36 -0
- package/dist/host/repo-guard.js +219 -0
- package/dist/host/secrets.d.ts +14 -0
- package/dist/host/secrets.js +133 -0
- package/dist/host/terminal.d.ts +32 -0
- package/dist/host/terminal.js +130 -0
- package/dist/host/test-guard.d.ts +6 -0
- package/dist/host/test-guard.js +15 -0
- package/dist/host/window.d.ts +4 -0
- package/dist/host/window.js +72 -0
- package/dist/host/wsb.d.ts +37 -0
- package/dist/host/wsb.js +101 -0
- package/dist/runtime/daemon.js +28494 -0
- package/dist/runtime/db.js +26387 -0
- package/dist/runtime/gitguard.js +84 -0
- package/dist/runtime/main.js +28622 -0
- package/dist/runtime/view.js +25841 -0
- package/dist/selftest/accounts.test.d.ts +2 -0
- package/dist/selftest/accounts.test.js +44 -0
- package/dist/selftest/agent-commands.test.d.ts +2 -0
- package/dist/selftest/agent-commands.test.js +47 -0
- package/dist/selftest/channel.test.d.ts +2 -0
- package/dist/selftest/channel.test.js +37 -0
- package/dist/selftest/cli.test.d.ts +2 -0
- package/dist/selftest/cli.test.js +118 -0
- package/dist/selftest/cmdline.test.d.ts +2 -0
- package/dist/selftest/cmdline.test.js +45 -0
- package/dist/selftest/config.test.d.ts +2 -0
- package/dist/selftest/config.test.js +38 -0
- package/dist/selftest/data.test.d.ts +2 -0
- package/dist/selftest/data.test.js +80 -0
- package/dist/selftest/detect.test.d.ts +2 -0
- package/dist/selftest/detect.test.js +58 -0
- package/dist/selftest/fixtures.d.ts +272 -0
- package/dist/selftest/fixtures.js +80 -0
- package/dist/selftest/generate.test.d.ts +2 -0
- package/dist/selftest/generate.test.js +63 -0
- package/dist/selftest/git-access.test.d.ts +2 -0
- package/dist/selftest/git-access.test.js +26 -0
- package/dist/selftest/guest-boot.test.d.ts +2 -0
- package/dist/selftest/guest-boot.test.js +76 -0
- package/dist/selftest/harness.d.ts +51 -0
- package/dist/selftest/harness.js +77 -0
- package/dist/selftest/host-sim.test.d.ts +2 -0
- package/dist/selftest/host-sim.test.js +93 -0
- package/dist/selftest/hostile-input.test.d.ts +2 -0
- package/dist/selftest/hostile-input.test.js +54 -0
- package/dist/selftest/index.d.ts +8 -0
- package/dist/selftest/index.js +155 -0
- package/dist/selftest/links.test.d.ts +2 -0
- package/dist/selftest/links.test.js +50 -0
- package/dist/selftest/live-daemon.test.d.ts +2 -0
- package/dist/selftest/live-daemon.test.js +91 -0
- package/dist/selftest/live-git.test.d.ts +2 -0
- package/dist/selftest/live-git.test.js +60 -0
- package/dist/selftest/live-projects.test.d.ts +2 -0
- package/dist/selftest/live-projects.test.js +127 -0
- package/dist/selftest/live.d.ts +65 -0
- package/dist/selftest/live.js +109 -0
- package/dist/selftest/local-config.test.d.ts +2 -0
- package/dist/selftest/local-config.test.js +107 -0
- package/dist/selftest/mirror.test.d.ts +2 -0
- package/dist/selftest/mirror.test.js +101 -0
- package/dist/selftest/network.test.d.ts +2 -0
- package/dist/selftest/network.test.js +28 -0
- package/dist/selftest/personalization.test.d.ts +2 -0
- package/dist/selftest/personalization.test.js +53 -0
- package/dist/selftest/projects.test.d.ts +2 -0
- package/dist/selftest/projects.test.js +254 -0
- package/dist/selftest/repair.test.d.ts +2 -0
- package/dist/selftest/repair.test.js +42 -0
- package/dist/selftest/repo-guard.test.d.ts +2 -0
- package/dist/selftest/repo-guard.test.js +63 -0
- package/dist/selftest/secrets.test.d.ts +2 -0
- package/dist/selftest/secrets.test.js +71 -0
- package/dist/selftest/setup.test.d.ts +2 -0
- package/dist/selftest/setup.test.js +46 -0
- package/dist/selftest/suite.d.ts +13 -0
- package/dist/selftest/suite.js +1 -0
- package/dist/selftest/sync.test.d.ts +2 -0
- package/dist/selftest/sync.test.js +94 -0
- package/dist/selftest/test-guard.test.d.ts +2 -0
- package/dist/selftest/test-guard.test.js +49 -0
- package/dist/selftest/toolchains.test.d.ts +2 -0
- package/dist/selftest/toolchains.test.js +103 -0
- package/dist/selftest/workspace.test.d.ts +2 -0
- package/dist/selftest/workspace.test.js +53 -0
- package/dist/shared/download.d.ts +60 -0
- package/dist/shared/download.js +215 -0
- package/dist/shared/guest-paths.d.ts +30 -0
- package/dist/shared/guest-paths.js +61 -0
- package/dist/shared/netrules.d.ts +18 -0
- package/dist/shared/netrules.js +98 -0
- package/dist/shared/paths.d.ts +14 -0
- package/dist/shared/paths.js +28 -0
- package/dist/shared/projects.d.ts +53 -0
- package/dist/shared/projects.js +67 -0
- package/dist/shared/pty-client.d.ts +86 -0
- package/dist/shared/pty-client.js +227 -0
- package/dist/shared/rundir.d.ts +39 -0
- package/dist/shared/rundir.js +94 -0
- package/dist/shared/safe-remove.d.ts +10 -0
- package/dist/shared/safe-remove.js +66 -0
- package/dist/shared/schema.d.ts +527 -0
- package/dist/shared/schema.js +90 -0
- package/dist/shared/system.d.ts +15 -0
- package/dist/shared/system.js +19 -0
- package/dist/shared/test-guard.d.ts +4 -0
- package/dist/shared/test-guard.js +37 -0
- package/dist/sync/claude-mem.d.ts +8 -0
- package/dist/sync/claude-mem.js +79 -0
- package/dist/sync/history.d.ts +41 -0
- package/dist/sync/history.js +161 -0
- package/dist/sync/watcher.d.ts +21 -0
- package/dist/sync/watcher.js +135 -0
- package/hooks/post-agent/README.txt +1 -0
- package/hooks/pre-provision/README.txt +1 -0
- package/package.json +91 -4
- package/sandbox/bootstrap.ps1 +258 -0
- package/sandbox/cpucap.ps1 +51 -0
- package/sandbox/gitshim.cs +35 -0
- package/sandbox/logon.cmd +18 -0
- package/sandbox/openssl.cs +42 -0
- package/sandbox/ptyhost.cs +614 -0
- package/sandbox/trust.cmd +35 -0
- package/sandbox/vswhere.cs +83 -0
- package/schemas/config.schema.json +1161 -0
- package/schemas/sandbox-config.schema.json +968 -0
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { projectUses } from '../guest/toolchains/versions.js';
|
|
2
|
+
/** Files that show a project uses a language (looked for in the workspace and one folder down). */
|
|
3
|
+
export const MARKERS = {
|
|
4
|
+
python: ['pyproject.toml', 'requirements.txt', 'setup.py', 'setup.cfg', 'Pipfile', 'uv.lock', 'poetry.lock', '.python-version', '*.py', '*.ipynb'],
|
|
5
|
+
rust: ['Cargo.toml', 'rust-toolchain', 'rust-toolchain.toml'],
|
|
6
|
+
msvc: ['*.vcxproj', 'CMakePresets.json', 'CMakeUserPresets.json'],
|
|
7
|
+
cpp: ['CMakeLists.txt', 'Makefile', 'meson.build', 'premake5.lua', 'Cargo.toml', '*.vcxproj', '*.c', '*.cpp', '*.cc', '*.h', '*.hpp'],
|
|
8
|
+
dotnet: ['*.sln', '*.slnx', '*.csproj', '*.fsproj', '*.vbproj', 'global.json', '*.cs'],
|
|
9
|
+
go: ['go.mod', 'go.work', '*.go'],
|
|
10
|
+
java: ['pom.xml', 'build.gradle', 'build.gradle.kts', 'settings.gradle', 'settings.gradle.kts', 'mvnw', 'gradlew', '.java-version', '.sdkmanrc', '*.java'],
|
|
11
|
+
ruby: ['Gemfile', '*.gemspec', '.ruby-version', '*.rb'],
|
|
12
|
+
php: ['composer.json', 'artisan', '.php-version', '*.php'],
|
|
13
|
+
deno: ['deno.json', 'deno.jsonc', 'deno.lock'],
|
|
14
|
+
// Windows PowerShell 5.1 runs any .ps1: PowerShell 7 is decided from script contents (hints.pwsh) or this PC.
|
|
15
|
+
pwsh: [],
|
|
16
|
+
};
|
|
17
|
+
export const AUTO_TOOLCHAINS = Object.keys(MARKERS);
|
|
18
|
+
/** Files of any ecosystem: a folder with none of them is no project yet. */
|
|
19
|
+
const PROJECT_FILES = [...new Set([...Object.values(MARKERS).flat(), 'package.json', 'deno.json', '*.ts', '*.js'])];
|
|
20
|
+
/**
|
|
21
|
+
* The decision per toolchain. true/false are kept; "auto" is on when the project has one of its marker files, or, in
|
|
22
|
+
* a folder that is no project yet, when this PC has the language installed. Rust needs a linker (MSVC or C/C++).
|
|
23
|
+
* hints: reasons found by reading files (a script that calls vcvars/vswhere) or about this PC ("builds Rust with MSVC"),
|
|
24
|
+
* which turn an "auto" toolchain on like a marker file does.
|
|
25
|
+
*/
|
|
26
|
+
export const decideToolchains = (settings, entries, pcHas, hints = {}) => {
|
|
27
|
+
const fresh = !projectUses(entries, PROJECT_FILES);
|
|
28
|
+
const decide = (name) => {
|
|
29
|
+
const setting = settings[name].enabled;
|
|
30
|
+
if (setting !== 'auto')
|
|
31
|
+
return { on: setting, reason: setting ? 'enabled in config' : 'disabled in config' };
|
|
32
|
+
const marker = MARKERS[name].map((m) => entries.find((e) => projectUses([e], [m]))).find(Boolean);
|
|
33
|
+
if (marker)
|
|
34
|
+
return { on: true, reason: marker };
|
|
35
|
+
if (hints[name])
|
|
36
|
+
return { on: true, reason: hints[name] };
|
|
37
|
+
if (fresh && pcHas.includes(name))
|
|
38
|
+
return { on: true, reason: 'installed on this PC (new folder)' };
|
|
39
|
+
return { on: false, reason: 'not used by this project' };
|
|
40
|
+
};
|
|
41
|
+
const result = Object.fromEntries(AUTO_TOOLCHAINS.map((name) => [name, decide(name)]));
|
|
42
|
+
// Rust links with MSVC when this PC does (its rustup host is *-msvc), otherwise with MinGW's gcc.
|
|
43
|
+
if (result.rust.on && settings.msvc.enabled === 'auto' && !result.msvc.on && pcHas.includes('msvc'))
|
|
44
|
+
result.msvc = { on: true, reason: 'Rust on this PC builds with MSVC' };
|
|
45
|
+
// MSVC is a 1-2 GB licensed download: "auto" only installs it once its licence is accepted.
|
|
46
|
+
if (settings.msvc.enabled === 'auto' && result.msvc.on && !settings.msvc.acceptLicense)
|
|
47
|
+
result.msvc = { on: false, reason: 'would be used (' + result.msvc.reason + '); set toolchains.msvc.acceptLicense to install it' };
|
|
48
|
+
if (result.rust.on && !result.msvc.on && !result.cpp.on && settings.cpp.enabled !== false)
|
|
49
|
+
result.cpp = { on: true, reason: 'the linker for Rust' };
|
|
50
|
+
return result;
|
|
51
|
+
};
|
|
52
|
+
/** The settings with every "auto" replaced by the decision (what the sandbox receives). */
|
|
53
|
+
export const resolveToolchains = (settings, decisions) => {
|
|
54
|
+
const out = structuredClone(settings);
|
|
55
|
+
for (const name of AUTO_TOOLCHAINS)
|
|
56
|
+
out[name].enabled = decisions[name].on;
|
|
57
|
+
return out;
|
|
58
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export declare const GB: number;
|
|
2
|
+
/** 1536 -> "1.5 KB". */
|
|
3
|
+
export declare const humanBytes: (bytes: number) => string;
|
|
4
|
+
/** Size on disk, never following links or junctions (a link counts as 0, so a planted junction cannot make us walk this PC's disk). */
|
|
5
|
+
export declare const sizeOf: (p: string) => number;
|
|
6
|
+
/** Free bytes on the drive that holds `dir` (which may not exist yet: the nearest existing parent is asked); null if unknown. */
|
|
7
|
+
export declare const freeBytesAt: (dir: string) => number | null;
|
|
8
|
+
export interface DiskUsage {
|
|
9
|
+
drive: string;
|
|
10
|
+
totalBytes: number;
|
|
11
|
+
freeBytes: number;
|
|
12
|
+
usedBytes: number;
|
|
13
|
+
holdsStorage: boolean;
|
|
14
|
+
}
|
|
15
|
+
/** Every local drive's size and free space, and which one holds the sandbox storage. */
|
|
16
|
+
export declare const diskUsage: (storageRoot: string) => DiskUsage[];
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
// Sizes and free space on disk, shared by `data`, `repair`, `setup` and the storage cleanup.
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import _ from 'lodash';
|
|
5
|
+
export const GB = 1024 ** 3;
|
|
6
|
+
/** 1536 -> "1.5 KB". */
|
|
7
|
+
export const humanBytes = (bytes) => {
|
|
8
|
+
const units = ['B', 'KB', 'MB', 'GB', 'TB'];
|
|
9
|
+
const i = bytes <= 0 ? 0 : Math.min(units.length - 1, Math.floor(Math.log(bytes) / Math.log(1024)));
|
|
10
|
+
const value = bytes / 1024 ** i;
|
|
11
|
+
return (i === 0 ? String(bytes) : value.toFixed(value < 10 ? 1 : 0)) + ' ' + units[i];
|
|
12
|
+
};
|
|
13
|
+
/** Size on disk, never following links or junctions (a link counts as 0, so a planted junction cannot make us walk this PC's disk). */
|
|
14
|
+
export const sizeOf = (p) => {
|
|
15
|
+
try {
|
|
16
|
+
const stat = fs.lstatSync(p);
|
|
17
|
+
if (stat.isSymbolicLink())
|
|
18
|
+
return 0;
|
|
19
|
+
if (!stat.isDirectory())
|
|
20
|
+
return stat.size;
|
|
21
|
+
return _.sumBy(fs.readdirSync(p, { withFileTypes: true }), (d) => (d.isSymbolicLink() ? 0 : sizeOf(path.join(p, d.name))));
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return 0;
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
/** Free bytes on the drive that holds `dir` (which may not exist yet: the nearest existing parent is asked); null if unknown. */
|
|
28
|
+
export const freeBytesAt = (dir) => {
|
|
29
|
+
let at = path.resolve(dir);
|
|
30
|
+
while (!fs.existsSync(at) && path.dirname(at) !== at)
|
|
31
|
+
at = path.dirname(at);
|
|
32
|
+
try {
|
|
33
|
+
const s = fs.statfsSync(at);
|
|
34
|
+
return s.bavail * s.bsize;
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
/** Every local drive's size and free space, and which one holds the sandbox storage. */
|
|
41
|
+
export const diskUsage = (storageRoot) => {
|
|
42
|
+
const storageDrive = path.parse(path.resolve(storageRoot)).root.toUpperCase();
|
|
43
|
+
return 'CDEFGHIJKLMNOPQRSTUVWXYZ'.split('').map((letter) => letter + ':\\').flatMap((drive) => {
|
|
44
|
+
try {
|
|
45
|
+
const s = fs.statfsSync(drive);
|
|
46
|
+
const totalBytes = s.blocks * s.bsize;
|
|
47
|
+
if (!totalBytes)
|
|
48
|
+
return [];
|
|
49
|
+
return [{ drive, totalBytes, freeBytes: s.bavail * s.bsize, usedBytes: totalBytes - s.bfree * s.bsize, holdsStorage: drive.toUpperCase() === storageDrive }];
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
return [];
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { Config, LocalConfigFile, Overrides } from './types.js';
|
|
2
|
+
export declare const LOCAL_CONFIG_NAME = ".sandbox-config.json";
|
|
3
|
+
/** Validates a folder's settings and resolves its relative paths against that folder. */
|
|
4
|
+
export declare const normalizeOverrides: (data: unknown, dir: string, source: string) => Overrides;
|
|
5
|
+
/**
|
|
6
|
+
* Protections a project file may only make stricter, never looser. A repo can ship the file, so it must not be able to
|
|
7
|
+
* switch off what you turned on (or turn on what you turned off). The strictest of the two values always wins.
|
|
8
|
+
*/
|
|
9
|
+
export declare const ON_IS_SAFER: string[];
|
|
10
|
+
export declare const OFF_IS_SAFER: string[];
|
|
11
|
+
export declare const GIT_STRICTNESS: Record<string, number>;
|
|
12
|
+
export declare const NEVER_LOOSER: string[];
|
|
13
|
+
/** Applies validated overrides. Mappings with the same guest folder replace the configured ones. */
|
|
14
|
+
export declare const applyOverrides: (config: Config, ov: Overrides) => Config;
|
|
15
|
+
/** Human-readable list of what a local config changes, with risky items flagged. */
|
|
16
|
+
export declare const describeOverrides: (ov: Overrides) => string[];
|
|
17
|
+
export declare const readLocalConfig: (dir: string) => LocalConfigFile | null;
|
|
18
|
+
export declare const trustStorePath: (storageRoot: string) => string;
|
|
19
|
+
export declare const isTrusted: (store: string, file: string, hash: string) => boolean;
|
|
20
|
+
export declare const saveTrust: (store: string, file: string, hash: string) => void;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
// A project's .sandbox-config.json: validated against the LocalOverrides schema (a safe subset of settings), applied
|
|
2
|
+
// over the user config, and only used once you have approved this exact version of the file.
|
|
3
|
+
import fs from 'node:fs';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import crypto from 'node:crypto';
|
|
6
|
+
import _ from 'lodash';
|
|
7
|
+
import { mergeConfig } from './config.js';
|
|
8
|
+
import { describeIssues, LocalOverrides } from './schema.js';
|
|
9
|
+
import { expandPath, fail, fileExists, parseJsonc, tryReadJson, writeJson } from './util.js';
|
|
10
|
+
export const LOCAL_CONFIG_NAME = '.sandbox-config.json';
|
|
11
|
+
/** Validates a folder's settings and resolves its relative paths against that folder. */
|
|
12
|
+
export const normalizeOverrides = (data, dir, source) => {
|
|
13
|
+
const parsed = LocalOverrides.safeParse(data);
|
|
14
|
+
if (!parsed.success)
|
|
15
|
+
fail(source + ' is not valid:\n - ' + describeIssues(parsed.error).join('\n - '));
|
|
16
|
+
const overrides = parsed.data;
|
|
17
|
+
const scripts = overrides.scripts?.map((s) => expandPath(s, dir));
|
|
18
|
+
const missing = scripts?.filter((s) => !fileExists(s)) ?? [];
|
|
19
|
+
if (missing.length)
|
|
20
|
+
fail(source + ' is not valid:\n - scripts: file not found: ' + missing.join(', '));
|
|
21
|
+
return { ...overrides, scripts, mappings: overrides.mappings?.map((m) => ({ ...m, host: expandPath(m.host, dir) })) };
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* Protections a project file may only make stricter, never looser. A repo can ship the file, so it must not be able to
|
|
25
|
+
* switch off what you turned on (or turn on what you turned off). The strictest of the two values always wins.
|
|
26
|
+
*/
|
|
27
|
+
export const ON_IS_SAFER = ['readOnly', 'network.blockPrivateRanges', 'sandbox.protectedClient', 'downloads.requireChecksum'];
|
|
28
|
+
export const OFF_IS_SAFER = ['sandbox.networking', 'sandbox.clipboard', 'sandbox.audioInput', 'sandbox.videoInput', 'sandbox.printerRedirection', 'sandbox.vGpu', 'claudeProfile.copyCredentials'];
|
|
29
|
+
export const GIT_STRICTNESS = { full: 0, readonly: 1, none: 2 };
|
|
30
|
+
export const NEVER_LOOSER = [...ON_IS_SAFER, ...OFF_IS_SAFER, 'provisioning.git.access'];
|
|
31
|
+
const keepStrictest = (yours, merged) => {
|
|
32
|
+
ON_IS_SAFER.forEach((p) => _.set(merged, p, Boolean(_.get(yours, p)) || Boolean(_.get(merged, p))));
|
|
33
|
+
OFF_IS_SAFER.forEach((p) => _.set(merged, p, Boolean(_.get(yours, p)) && Boolean(_.get(merged, p))));
|
|
34
|
+
if (GIT_STRICTNESS[yours.provisioning.git.access] > GIT_STRICTNESS[merged.provisioning.git.access])
|
|
35
|
+
merged.provisioning.git.access = yours.provisioning.git.access;
|
|
36
|
+
};
|
|
37
|
+
/** Applies validated overrides. Mappings with the same guest folder replace the configured ones. */
|
|
38
|
+
export const applyOverrides = (config, ov) => {
|
|
39
|
+
const { harness, mappings, scripts: _scripts, $schema: _schema, ...rest } = ov;
|
|
40
|
+
const next = mergeConfig(config, rest);
|
|
41
|
+
keepStrictest(config, next);
|
|
42
|
+
if (harness)
|
|
43
|
+
next.defaultHarness = harness;
|
|
44
|
+
if (mappings)
|
|
45
|
+
next.mappings = [..._.reject(config.mappings, (m) => mappings.some((o) => o.guest.toLowerCase() === m.guest.toLowerCase())), ...mappings];
|
|
46
|
+
return next;
|
|
47
|
+
};
|
|
48
|
+
const flatten = (value, prefix = '') => _.isPlainObject(value) ? Object.entries(value).flatMap(([k, v]) => flatten(v, prefix ? prefix + '.' + k : k)) : [prefix + ' = ' + JSON.stringify(value)];
|
|
49
|
+
/** Human-readable list of what a local config changes, with risky items flagged. */
|
|
50
|
+
export const describeOverrides = (ov) => {
|
|
51
|
+
const { harness, mappings = [], scripts = [], $schema: _schema, ...sections } = ov;
|
|
52
|
+
const lines = [
|
|
53
|
+
...(harness ? ['agent = ' + harness] : []),
|
|
54
|
+
...mappings.map((m) => (m.readOnly ? 'read-only' : 'READ/WRITE') + ' folder ' + m.host + ' -> ' + m.guest),
|
|
55
|
+
...scripts.map((s) => 'runs inside the sandbox: ' + s),
|
|
56
|
+
...flatten(sections),
|
|
57
|
+
];
|
|
58
|
+
const risky = _.compact([
|
|
59
|
+
mappings.some((m) => !m.readOnly) && 'a READ/WRITE mapping lets the agent change files outside your workspace',
|
|
60
|
+
]);
|
|
61
|
+
// These are only used when they are stricter than your own settings, so a project can never loosen them.
|
|
62
|
+
const limited = NEVER_LOOSER.filter((p) => _.has(sections, p)).map((p) => p + ' is only used if it is stricter than your own setting');
|
|
63
|
+
return [...lines, ...risky.map((r) => '!! ' + r), ...limited.map((r) => ' ' + r)];
|
|
64
|
+
};
|
|
65
|
+
export const readLocalConfig = (dir) => {
|
|
66
|
+
const file = path.join(dir, LOCAL_CONFIG_NAME);
|
|
67
|
+
if (!fileExists(file))
|
|
68
|
+
return null;
|
|
69
|
+
const raw = fs.readFileSync(file);
|
|
70
|
+
return { path: file, hash: crypto.createHash('sha256').update(raw).digest('hex'), data: parseJsonc(raw.toString('utf8'), file) };
|
|
71
|
+
};
|
|
72
|
+
// ---- approvals (host-only: <storage>\trusted-configs.json) ----------------------------------------------------------
|
|
73
|
+
export const trustStorePath = (storageRoot) => path.join(storageRoot, 'trusted-configs.json');
|
|
74
|
+
const loadTrust = (store) => tryReadJson(store) ?? {};
|
|
75
|
+
const key = (file) => path.resolve(file).toLowerCase();
|
|
76
|
+
export const isTrusted = (store, file, hash) => loadTrust(store)[key(file)] === hash;
|
|
77
|
+
export const saveTrust = (store, file, hash) => writeJson(store, { ...loadTrust(store), [key(file)]: hash });
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Config } from './types.js';
|
|
2
|
+
/** The protections of a running sandbox, by setting path (`sandbox.networking`, `provisioning.git.access`, ...). */
|
|
3
|
+
export type Protections = Record<string, boolean | string>;
|
|
4
|
+
export declare const protectionsOf: (config: Config) => Protections;
|
|
5
|
+
export interface JoinCheck {
|
|
6
|
+
/** Settings this project needs stricter than the running sandbox: the launch is refused. */
|
|
7
|
+
stricter: string[];
|
|
8
|
+
/** Settings it would have looser: it gets the sandbox's (stricter) value; shown as a note. */
|
|
9
|
+
looser: string[];
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Compares a project's effective protections with the running sandbox's. Hub projects are always read/write
|
|
13
|
+
* (Windows Sandbox maps the hub once, read/write), so a read-only project counts as stricter.
|
|
14
|
+
*/
|
|
15
|
+
export declare const checkJoin: (running: Protections, wanted: Protections) => JoinCheck;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
// Joining a running sandbox from another project. Its protections (network, LAN block, git access, clipboard, the
|
|
2
|
+
// .wsb device settings, read-only) are machine-wide: they were fixed when the sandbox booted for the first project.
|
|
3
|
+
// A second project may never loosen them, and a project that needs a STRICTER setting than the running sandbox has
|
|
4
|
+
// cannot get it there without changing it for the sessions already running, so that launch is refused with a clear
|
|
5
|
+
// message. A project asking for less than the sandbox has simply runs with the sandbox's (stricter) setting.
|
|
6
|
+
// Pure: the host checks it before registering a project, the tests drive it directly.
|
|
7
|
+
import _ from 'lodash';
|
|
8
|
+
import { GIT_STRICTNESS, NEVER_LOOSER, OFF_IS_SAFER, ON_IS_SAFER } from './local-config.js';
|
|
9
|
+
export const protectionsOf = (config) => Object.fromEntries(NEVER_LOOSER.map((p) => [p, _.get(config, p)]));
|
|
10
|
+
/** 1 = `wanted` is stricter than `running`, -1 = looser, 0 = the same. */
|
|
11
|
+
const compare = (setting, running, wanted) => {
|
|
12
|
+
if (setting === 'provisioning.git.access')
|
|
13
|
+
return Math.sign((GIT_STRICTNESS[String(wanted)] ?? 0) - (GIT_STRICTNESS[String(running)] ?? 0));
|
|
14
|
+
if (ON_IS_SAFER.includes(setting))
|
|
15
|
+
return Number(Boolean(wanted)) - Number(Boolean(running));
|
|
16
|
+
if (OFF_IS_SAFER.includes(setting))
|
|
17
|
+
return Number(Boolean(running)) - Number(Boolean(wanted));
|
|
18
|
+
return 0;
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Compares a project's effective protections with the running sandbox's. Hub projects are always read/write
|
|
22
|
+
* (Windows Sandbox maps the hub once, read/write), so a read-only project counts as stricter.
|
|
23
|
+
*/
|
|
24
|
+
export const checkJoin = (running, wanted) => {
|
|
25
|
+
const stricter = [];
|
|
26
|
+
const looser = [];
|
|
27
|
+
for (const setting of NEVER_LOOSER) {
|
|
28
|
+
const result = compare(setting, setting === 'readOnly' ? false : running[setting], wanted[setting]);
|
|
29
|
+
if (result > 0)
|
|
30
|
+
stricter.push(setting + ' = ' + JSON.stringify(wanted[setting]) + ' (the running sandbox has ' + JSON.stringify(setting === 'readOnly' ? false : running[setting]) + ')');
|
|
31
|
+
if (result < 0)
|
|
32
|
+
looser.push(setting + ' stays ' + JSON.stringify(running[setting]));
|
|
33
|
+
}
|
|
34
|
+
return { stricter, looser };
|
|
35
|
+
};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
/** A yes/no question (default no). */
|
|
2
|
+
export declare const askYesNo: (question: string, defaultYes?: boolean) => Promise<boolean>;
|
|
3
|
+
/** Asks the user to type `expected` (a stronger confirmation than yes/no). */
|
|
4
|
+
export declare const askTyped: (question: string, expected: string) => Promise<boolean>;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// Questions asked on the terminal, all through @inquirer/prompts. Without an interactive terminal the answer is always "no".
|
|
2
|
+
import { confirm, input } from '@inquirer/prompts';
|
|
3
|
+
/** A yes/no question (default no). */
|
|
4
|
+
export const askYesNo = async (question, defaultYes = false) => {
|
|
5
|
+
if (!process.stdin.isTTY)
|
|
6
|
+
return false;
|
|
7
|
+
return confirm({ message: question, default: defaultYes });
|
|
8
|
+
};
|
|
9
|
+
/** Asks the user to type `expected` (a stronger confirmation than yes/no). */
|
|
10
|
+
export const askTyped = async (question, expected) => {
|
|
11
|
+
if (!process.stdin.isTTY)
|
|
12
|
+
return false;
|
|
13
|
+
const answer = await input({ message: question + ' Type "' + expected + '" to confirm:' });
|
|
14
|
+
return answer.trim().toLowerCase() === expected;
|
|
15
|
+
};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
/** A read/write folder mapped into the sandbox must not contain, or sit inside, any protected folder. */
|
|
2
|
+
export declare const assertSafeMapping: (folder: string, packageRoot: string, storageRoot: string) => void;
|
|
3
|
+
/** The agent gets read/write access to the workspace, so refuse folders that would let it reach the tool itself, its storage, or the OS. */
|
|
4
|
+
export declare const assertSafeWorkspace: (workspace: string, packageRoot: string, storageRoot: string) => void;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// Which folders may be shared with the sandbox. The agent gets read/write access to what is mapped, so nothing that
|
|
2
|
+
// would let it reach this tool, its storage, your settings or the OS may be mapped.
|
|
3
|
+
import { userDir } from './config.js';
|
|
4
|
+
import { fail, isInsideOrEqual, isRootPath, isUserProfile } from './util.js';
|
|
5
|
+
/** Folders the agent must never be able to write: the tool itself, its storage and your settings for it. */
|
|
6
|
+
const protectedFolders = (packageRoot, storageRoot) => [
|
|
7
|
+
['this tool\'s install folder', packageRoot],
|
|
8
|
+
['the sandbox storage folder', storageRoot],
|
|
9
|
+
['your sandbox settings folder', userDir()],
|
|
10
|
+
];
|
|
11
|
+
/** A read/write folder mapped into the sandbox must not contain, or sit inside, any protected folder. */
|
|
12
|
+
export const assertSafeMapping = (folder, packageRoot, storageRoot) => {
|
|
13
|
+
if (isRootPath(folder) || isUserProfile(folder))
|
|
14
|
+
fail('A whole drive or user profile cannot be mapped into the sandbox: ' + folder, 'Map a specific folder instead.');
|
|
15
|
+
for (const [label, dir] of protectedFolders(packageRoot, storageRoot)) {
|
|
16
|
+
if (isInsideOrEqual(dir, folder) || isInsideOrEqual(folder, dir))
|
|
17
|
+
fail(folder + ' cannot be mapped into the sandbox: it overlaps ' + label + ' (' + dir + ').', 'Map a folder that is not inside (and does not contain) ' + dir + '.');
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
/** The agent gets read/write access to the workspace, so refuse folders that would let it reach the tool itself, its storage, or the OS. */
|
|
21
|
+
export const assertSafeWorkspace = (workspace, packageRoot, storageRoot) => {
|
|
22
|
+
if (isRootPath(workspace))
|
|
23
|
+
fail('A whole drive cannot be the workspace: ' + workspace, 'Run sandbox claude from a project folder (or pass --workspace <folder>).');
|
|
24
|
+
if (isUserProfile(workspace))
|
|
25
|
+
fail('Your whole user profile cannot be the workspace: ' + workspace, 'Run sandbox claude from a project folder (or pass --workspace <folder>).');
|
|
26
|
+
for (const [label, dir] of protectedFolders(packageRoot, storageRoot)) {
|
|
27
|
+
if (isInsideOrEqual(dir, workspace))
|
|
28
|
+
fail(workspace + ' cannot be the workspace: it is inside ' + label + ' (' + dir + '), so the agent could change the code that runs on this PC.', dir === packageRoot ? 'Developing windows-development-sandbox itself? Install it as a copy instead of a link: run `npm run install:global` in the repository, then sandbox claude works there.' : 'Run sandbox claude from a project folder somewhere else.');
|
|
29
|
+
if (isInsideOrEqual(workspace, dir))
|
|
30
|
+
fail(workspace + ' cannot be the workspace: it contains ' + label + ' (' + dir + '), which the agent must not be able to change.', 'Run sandbox claude from a project folder that does not contain it.');
|
|
31
|
+
}
|
|
32
|
+
for (const name of ['WINDIR', 'SystemRoot', 'ProgramFiles', 'ProgramFiles(x86)', 'ProgramData']) {
|
|
33
|
+
const dir = process.env[name];
|
|
34
|
+
if (dir && isInsideOrEqual(dir, workspace))
|
|
35
|
+
fail('A system folder cannot be the workspace: ' + workspace, 'Run sandbox claude from a project folder.');
|
|
36
|
+
}
|
|
37
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare const GuestPath: z.ZodString;
|
|
3
|
+
export declare const Name: z.ZodString;
|
|
4
|
+
export declare const Strings: z.ZodArray<z.ZodString>;
|
|
5
|
+
export declare const toggle: (description: string) => z.ZodObject<{
|
|
6
|
+
enabled: z.ZodBoolean;
|
|
7
|
+
}, z.core.$strict>;
|
|
8
|
+
export declare const SchemaRef: z.ZodString;
|
|
9
|
+
export declare const GitAccess: z.ZodEnum<{
|
|
10
|
+
readonly: "readonly";
|
|
11
|
+
full: "full";
|
|
12
|
+
none: "none";
|
|
13
|
+
}>;
|
|
14
|
+
/** true, false, or "auto": only when the project uses it (found from files like go.mod in the workspace or one level down). */
|
|
15
|
+
export declare const Enabled: z.ZodUnion<readonly [z.ZodBoolean, z.ZodLiteral<"auto">]>;
|
|
16
|
+
export declare const enabled: (what: string, markers: string) => z.ZodUnion<readonly [z.ZodBoolean, z.ZodLiteral<"auto">]>;
|
|
17
|
+
export declare const Packages: (what: string, example: string) => z.ZodArray<z.ZodString>;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// Building blocks shared by the settings schemas.
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { isValidGuestPath } from '../../shared/guest-paths.js';
|
|
4
|
+
// Rules (and RESERVED_GUEST) live in shared/guest-paths.ts: the host re-checks them before writing the .wsb.
|
|
5
|
+
export const GuestPath = z.string().refine(isValidGuestPath, 'reserved or invalid guest path (a folder under C:\\ other than Windows, Program Files, Users, AgentData, Mirror, ..., or on drive D: to Z:)');
|
|
6
|
+
export const Name = z.string().regex(/^[A-Za-z0-9_-]+$/, 'letters, numbers, - and _ only');
|
|
7
|
+
export const Strings = z.array(z.string());
|
|
8
|
+
export const toggle = (description) => z.strictObject({ enabled: z.boolean().describe(description) });
|
|
9
|
+
export const SchemaRef = z.string().describe('Path or URL of the JSON Schema for editor autocomplete and docs.');
|
|
10
|
+
export const GitAccess = z.enum(['full', 'readonly', 'none'])
|
|
11
|
+
.describe('full: normal git. readonly: status/log/diff/show/blame only (no commit, push, checkout, ...). none: no git at all; .git is hidden from the agent.');
|
|
12
|
+
/** true, false, or "auto": only when the project uses it (found from files like go.mod in the workspace or one level down). */
|
|
13
|
+
export const Enabled = z.union([z.boolean(), z.literal('auto')]);
|
|
14
|
+
export const enabled = (what, markers) => Enabled.describe(what + ' true, false, or "auto" = only when the project has ' + markers + '.');
|
|
15
|
+
export const Packages = (what, example) => Strings.describe(what + ', installed once and kept (e.g. ' + example + ').');
|