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,30 @@
|
|
|
1
|
+
/** Guest folders no mapping may use: the OS, the sandbox's own folders and the mirror root. */
|
|
2
|
+
export declare const RESERVED_GUEST: RegExp;
|
|
3
|
+
/** Where folders for other drive letters really live inside the sandbox: C:\Mirror\<letter>. */
|
|
4
|
+
export declare const MIRROR_ROOT = "C:\\Mirror";
|
|
5
|
+
/** Letters a mirrored path may use. Never C: (the sandbox's own disk); A:/B: are left alone (floppy-era tools). */
|
|
6
|
+
export declare const MIRROR_LETTER: RegExp;
|
|
7
|
+
/** The upper-case drive letter of an absolute guest path (F:\x -> F), or null. */
|
|
8
|
+
export declare const guestDrive: (guest: string) => string | null;
|
|
9
|
+
/**
|
|
10
|
+
* A folder the sandbox can show a host folder at: C:\<not reserved>\... or <D-Z>:\..., never a drive root,
|
|
11
|
+
* no '..' or empty segments, no characters Windows rejects in paths.
|
|
12
|
+
*/
|
|
13
|
+
export declare const isValidGuestPath: (guest: string) => boolean;
|
|
14
|
+
/** Where a guest path really is inside the sandbox (the .wsb SandboxFolder): C: paths as-is, F:\x -> C:\Mirror\F\x. */
|
|
15
|
+
export declare const sandboxFolder: (guest: string) => string;
|
|
16
|
+
export interface SubstDrive {
|
|
17
|
+
letter: string;
|
|
18
|
+
target: string;
|
|
19
|
+
}
|
|
20
|
+
/** The subst drives the guest must create at boot for these guest paths, one per letter, sorted. */
|
|
21
|
+
export declare const substDrives: (guests: string[]) => SubstDrive[];
|
|
22
|
+
/**
|
|
23
|
+
* guestWorkspace "mirror": the workspace at the same path as on this PC, so absolute paths (configs, build caches,
|
|
24
|
+
* cargo fingerprints, Claude's project folder) match. Falls back to `fallback` (C:\Workspace\<name>) when the host
|
|
25
|
+
* path cannot be used inside the sandbox (C:\Users\..., a UNC path, A:/B:, odd characters), with a note saying why.
|
|
26
|
+
*/
|
|
27
|
+
export declare const planMirrorWorkspace: (workspaceHost: string, fallback: string) => {
|
|
28
|
+
guest: string;
|
|
29
|
+
note: string | null;
|
|
30
|
+
};
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
// Guest paths on drive letters other than C:. Windows Sandbox can only map folders onto its own C: drive, so a
|
|
2
|
+
// guest path like F:\SteamLibrary\x is mapped to C:\Mirror\F\SteamLibrary\x and, at boot (bootstrap.ps1, before
|
|
3
|
+
// anything else uses the workspace), `subst F: C:\Mirror\F` makes it appear at F:\SteamLibrary\x.
|
|
4
|
+
// Pure functions only: used by the schema, the host (.wsb, session.json) and history sync.
|
|
5
|
+
/** Guest folders no mapping may use: the OS, the sandbox's own folders and the mirror root. */
|
|
6
|
+
export const RESERVED_GUEST = /^C:\\(?:Windows|Program Files|Program Files \(x86\)|ProgramData|Users|AgentLaunch|AgentData|HostTools|nvm|Mirror)(?:\\|$)/i;
|
|
7
|
+
/** Where folders for other drive letters really live inside the sandbox: C:\Mirror\<letter>. */
|
|
8
|
+
export const MIRROR_ROOT = 'C:\\Mirror';
|
|
9
|
+
/** Letters a mirrored path may use. Never C: (the sandbox's own disk); A:/B: are left alone (floppy-era tools). */
|
|
10
|
+
export const MIRROR_LETTER = /^[D-Z]$/;
|
|
11
|
+
const DRIVE_PATH = /^([A-Za-z]):\\(.*)$/;
|
|
12
|
+
// No other ':' (alternate data streams), no wildcards or pipes, no control characters, no forward slashes.
|
|
13
|
+
const BAD_CHARS = /[<>:"|?*/\x00-\x1f]/;
|
|
14
|
+
/** The upper-case drive letter of an absolute guest path (F:\x -> F), or null. */
|
|
15
|
+
export const guestDrive = (guest) => DRIVE_PATH.exec(guest)?.[1].toUpperCase() ?? null;
|
|
16
|
+
/**
|
|
17
|
+
* A folder the sandbox can show a host folder at: C:\<not reserved>\... or <D-Z>:\..., never a drive root,
|
|
18
|
+
* no '..' or empty segments, no characters Windows rejects in paths.
|
|
19
|
+
*/
|
|
20
|
+
export const isValidGuestPath = (guest) => {
|
|
21
|
+
const m = DRIVE_PATH.exec(guest);
|
|
22
|
+
if (!m)
|
|
23
|
+
return false;
|
|
24
|
+
const letter = m[1].toUpperCase();
|
|
25
|
+
const rest = m[2].replace(/\\+$/, '');
|
|
26
|
+
if (rest === '' || BAD_CHARS.test(rest))
|
|
27
|
+
return false;
|
|
28
|
+
if (rest.split('\\').some((segment) => segment === '' || segment === '.' || segment === '..' || /[. ]$/.test(segment)))
|
|
29
|
+
return false;
|
|
30
|
+
if (letter === 'C')
|
|
31
|
+
return !RESERVED_GUEST.test('C:\\' + rest);
|
|
32
|
+
return MIRROR_LETTER.test(letter);
|
|
33
|
+
};
|
|
34
|
+
/** Where a guest path really is inside the sandbox (the .wsb SandboxFolder): C: paths as-is, F:\x -> C:\Mirror\F\x. */
|
|
35
|
+
export const sandboxFolder = (guest) => {
|
|
36
|
+
const m = DRIVE_PATH.exec(guest);
|
|
37
|
+
if (!m || m[1].toUpperCase() === 'C')
|
|
38
|
+
return guest;
|
|
39
|
+
return MIRROR_ROOT + '\\' + m[1].toUpperCase() + (m[2] ? '\\' + m[2] : '');
|
|
40
|
+
};
|
|
41
|
+
/** The subst drives the guest must create at boot for these guest paths, one per letter, sorted. */
|
|
42
|
+
export const substDrives = (guests) => {
|
|
43
|
+
const letters = [...new Set(guests.map(guestDrive).filter((l) => l !== null && l !== 'C'))].sort();
|
|
44
|
+
return letters.map((letter) => ({ letter, target: MIRROR_ROOT + '\\' + letter }));
|
|
45
|
+
};
|
|
46
|
+
/**
|
|
47
|
+
* guestWorkspace "mirror": the workspace at the same path as on this PC, so absolute paths (configs, build caches,
|
|
48
|
+
* cargo fingerprints, Claude's project folder) match. Falls back to `fallback` (C:\Workspace\<name>) when the host
|
|
49
|
+
* path cannot be used inside the sandbox (C:\Users\..., a UNC path, A:/B:, odd characters), with a note saying why.
|
|
50
|
+
*/
|
|
51
|
+
export const planMirrorWorkspace = (workspaceHost, fallback) => {
|
|
52
|
+
const host = workspaceHost.replace(/\\+$/, '');
|
|
53
|
+
if (isValidGuestPath(host)) {
|
|
54
|
+
const letter = guestDrive(host);
|
|
55
|
+
return { guest: letter + host.slice(1), note: letter === 'C' ? null : 'guestWorkspace "mirror": ' + host + ' is mapped to ' + sandboxFolder(letter + host.slice(1)) + ' and shown as ' + letter + ': (subst) inside the sandbox.' };
|
|
56
|
+
}
|
|
57
|
+
const why = !guestDrive(host) ? 'it is not on a drive letter'
|
|
58
|
+
: guestDrive(host) === 'C' && RESERVED_GUEST.test(host) ? 'that folder is reserved inside the sandbox (Windows, Program Files, Users, ...)'
|
|
59
|
+
: 'the sandbox cannot show a folder at that path';
|
|
60
|
+
return { guest: fallback, note: 'guestWorkspace "mirror": ' + host + ' cannot appear at the same path (' + why + '); using ' + fallback + ' instead.' };
|
|
61
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/** Private, carrier-grade NAT (Tailscale and similar live here), link-local and multicast ranges. */
|
|
2
|
+
export declare const PRIVATE_V4: string[];
|
|
3
|
+
export declare const PRIVATE_V6: string[];
|
|
4
|
+
export declare const RULE_NAMES: string[];
|
|
5
|
+
export declare const isIPv4: (ip: string) => boolean;
|
|
6
|
+
export declare const ipToInt: (ip: string) => number;
|
|
7
|
+
export declare const intToIp: (n: number) => string;
|
|
8
|
+
export declare const cidrToRange: (cidr: string) => [number, number];
|
|
9
|
+
export declare const subtractIps: (ranges: [number, number][], ips: string[]) => [number, number][];
|
|
10
|
+
export declare const formatRange: (range: [number, number]) => string;
|
|
11
|
+
export declare const isPrivateV4: (ip: string) => boolean;
|
|
12
|
+
export declare const parseDefaultGateways: (routePrint: string) => string[];
|
|
13
|
+
/** The IPv4 servers in a dns.getServers() list ('8.8.8.8', '8.8.8.8:1053', '[::1]:53'); IPv6 ones are dropped. */
|
|
14
|
+
export declare const ipv4DnsServers: (servers: string[]) => string[];
|
|
15
|
+
/** Fallback only: the "DNS Servers" label is English, so this finds nothing on localised Windows (dns.getServers() does). */
|
|
16
|
+
export declare const parseDnsServers: (ipconfigAll: string) => string[];
|
|
17
|
+
/** netsh argument lists. Private ranges are blocked EXCEPT DNS/DHCP to the sandbox's own gateway, so name resolution keeps working. */
|
|
18
|
+
export declare const buildFirewallCommands: (exemptIps: string[]) => string[][];
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/** Private, carrier-grade NAT (Tailscale and similar live here), link-local and multicast ranges. */
|
|
2
|
+
export const PRIVATE_V4 = ['10.0.0.0/8', '172.16.0.0/12', '192.168.0.0/16', '100.64.0.0/10', '169.254.0.0/16', '224.0.0.0/4'];
|
|
3
|
+
export const PRIVATE_V6 = ['fc00::/7', 'fe80::/10', 'ff00::/8'];
|
|
4
|
+
export const RULE_NAMES = ['AgentSandbox-Block-Private', 'AgentSandbox-Block-IPv6-Local', 'AgentSandbox-Block-SMB', 'AgentSandbox-Gateway-TCP', 'AgentSandbox-Gateway-UDP'];
|
|
5
|
+
export const isIPv4 = (ip) => {
|
|
6
|
+
const parts = ip.split('.');
|
|
7
|
+
return parts.length === 4 && parts.every((p) => /^\d{1,3}$/.test(p) && Number(p) <= 255);
|
|
8
|
+
};
|
|
9
|
+
export const ipToInt = (ip) => {
|
|
10
|
+
if (!isIPv4(ip))
|
|
11
|
+
throw new Error('Invalid IPv4 address: ' + ip);
|
|
12
|
+
const p = ip.split('.').map(Number);
|
|
13
|
+
return p[0] * 16777216 + p[1] * 65536 + p[2] * 256 + p[3];
|
|
14
|
+
};
|
|
15
|
+
export const intToIp = (n) => {
|
|
16
|
+
return [Math.floor(n / 16777216) % 256, Math.floor(n / 65536) % 256, Math.floor(n / 256) % 256, n % 256].join('.');
|
|
17
|
+
};
|
|
18
|
+
export const cidrToRange = (cidr) => {
|
|
19
|
+
const [ip, bits] = cidr.split('/');
|
|
20
|
+
const size = 2 ** (32 - Number(bits));
|
|
21
|
+
const start = Math.floor(ipToInt(ip) / size) * size;
|
|
22
|
+
return [start, start + size - 1];
|
|
23
|
+
};
|
|
24
|
+
export const subtractIps = (ranges, ips) => {
|
|
25
|
+
let result = ranges.map((r) => [r[0], r[1]]);
|
|
26
|
+
for (const ip of ips) {
|
|
27
|
+
const n = ipToInt(ip);
|
|
28
|
+
const next = [];
|
|
29
|
+
for (const [start, end] of result) {
|
|
30
|
+
if (n < start || n > end) {
|
|
31
|
+
next.push([start, end]);
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
if (n > start)
|
|
35
|
+
next.push([start, n - 1]);
|
|
36
|
+
if (n < end)
|
|
37
|
+
next.push([n + 1, end]);
|
|
38
|
+
}
|
|
39
|
+
result = next;
|
|
40
|
+
}
|
|
41
|
+
return result;
|
|
42
|
+
};
|
|
43
|
+
export const formatRange = (range) => {
|
|
44
|
+
return range[0] === range[1] ? intToIp(range[0]) : intToIp(range[0]) + '-' + intToIp(range[1]);
|
|
45
|
+
};
|
|
46
|
+
export const isPrivateV4 = (ip) => {
|
|
47
|
+
const n = ipToInt(ip);
|
|
48
|
+
return PRIVATE_V4.some((c) => { const [s, e] = cidrToRange(c); return n >= s && n <= e; });
|
|
49
|
+
};
|
|
50
|
+
export const parseDefaultGateways = (routePrint) => {
|
|
51
|
+
const found = [];
|
|
52
|
+
for (const line of routePrint.split(/\r?\n/)) {
|
|
53
|
+
const m = /^\s*0\.0\.0\.0\s+0\.0\.0\.0\s+(\d{1,3}(?:\.\d{1,3}){3})\s/.exec(line);
|
|
54
|
+
if (m && isIPv4(m[1]))
|
|
55
|
+
found.push(m[1]);
|
|
56
|
+
}
|
|
57
|
+
return found;
|
|
58
|
+
};
|
|
59
|
+
/** The IPv4 servers in a dns.getServers() list ('8.8.8.8', '8.8.8.8:1053', '[::1]:53'); IPv6 ones are dropped. */
|
|
60
|
+
export const ipv4DnsServers = (servers) => servers.map((s) => s.replace(/:\d+$/, '')).filter(isIPv4);
|
|
61
|
+
/** Fallback only: the "DNS Servers" label is English, so this finds nothing on localised Windows (dns.getServers() does). */
|
|
62
|
+
export const parseDnsServers = (ipconfigAll) => {
|
|
63
|
+
const found = [];
|
|
64
|
+
let inDns = false;
|
|
65
|
+
for (const line of ipconfigAll.split(/\r?\n/)) {
|
|
66
|
+
if (/DNS Servers/i.test(line)) {
|
|
67
|
+
inDns = true;
|
|
68
|
+
for (const m of line.matchAll(/(\d{1,3}(?:\.\d{1,3}){3})/g))
|
|
69
|
+
if (isIPv4(m[1]))
|
|
70
|
+
found.push(m[1]);
|
|
71
|
+
}
|
|
72
|
+
else if (inDns && /^\s+\d{1,3}(?:\.\d{1,3}){3}\s*$/.test(line)) {
|
|
73
|
+
found.push(line.trim());
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
inDns = false;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return found;
|
|
80
|
+
};
|
|
81
|
+
/** netsh argument lists. Private ranges are blocked EXCEPT DNS/DHCP to the sandbox's own gateway, so name resolution keeps working. */
|
|
82
|
+
export const buildFirewallCommands = (exemptIps) => {
|
|
83
|
+
const exempt = [...new Set(exemptIps.filter((ip) => isIPv4(ip) && isPrivateV4(ip)))];
|
|
84
|
+
const v4 = subtractIps(PRIVATE_V4.map(cidrToRange), exempt).map(formatRange);
|
|
85
|
+
const add = (name, extra) => ['advfirewall', 'firewall', 'add', 'rule', 'name=' + name, 'dir=out', 'action=block', 'enable=yes', 'profile=any', ...extra];
|
|
86
|
+
const commands = [];
|
|
87
|
+
for (const name of RULE_NAMES)
|
|
88
|
+
commands.push(['advfirewall', 'firewall', 'delete', 'rule', 'name=' + name]);
|
|
89
|
+
commands.push(['advfirewall', 'set', 'allprofiles', 'state', 'on']);
|
|
90
|
+
commands.push(add('AgentSandbox-Block-Private', ['protocol=any', 'remoteip=' + v4.join(',')]));
|
|
91
|
+
commands.push(add('AgentSandbox-Block-IPv6-Local', ['protocol=any', 'remoteip=' + PRIVATE_V6.join(',')]));
|
|
92
|
+
commands.push(add('AgentSandbox-Block-SMB', ['protocol=tcp', 'remoteport=135,139,445']));
|
|
93
|
+
if (exempt.length > 0) {
|
|
94
|
+
commands.push(add('AgentSandbox-Gateway-TCP', ['protocol=tcp', 'remoteip=' + exempt.join(','), 'remoteport=1-52,54-65535']));
|
|
95
|
+
commands.push(add('AgentSandbox-Gateway-UDP', ['protocol=udp', 'remoteip=' + exempt.join(','), 'remoteport=1-52,54-66,69-65535']));
|
|
96
|
+
}
|
|
97
|
+
return commands;
|
|
98
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/** Claude Code's per-project folder name: every non-alphanumeric character becomes '-' (F:\A\b -> F--A-b). */
|
|
2
|
+
export declare const projectFolderName: (workspace: string) => string;
|
|
3
|
+
/**
|
|
4
|
+
* Every path the guest may know its workspace by, the real one first: a mirrored F:\A\b is a subst drive onto
|
|
5
|
+
* C:\Mirror\F\A\b, and programs that resolve real paths (realpath, GetFinalPathNameByHandle) report that one.
|
|
6
|
+
*/
|
|
7
|
+
export declare const guestWorkspaceAliases: (guestWorkspace: string) => string[];
|
|
8
|
+
/**
|
|
9
|
+
* A file or folder name that is safe to recreate on this PC. The sandbox can create names Windows would treat as devices
|
|
10
|
+
* (CON.jsonl opens the console), as streams (a:b), or that end in a dot or space (silently renamed); none of them are copied.
|
|
11
|
+
*/
|
|
12
|
+
export declare const isSafeFileName: (name: string) => boolean;
|
|
13
|
+
/** Rewrites `from` to `to` wherever it appears as a whole path (raw, JSON-escaped or with forward slashes). */
|
|
14
|
+
export declare const translatePaths: (text: string, from: string, to: string) => string;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// Path translation between this PC and the sandbox (shared by the host history sync and the guest plugin fix-up).
|
|
2
|
+
import { sandboxFolder } from './guest-paths.js';
|
|
3
|
+
/** Claude Code's per-project folder name: every non-alphanumeric character becomes '-' (F:\A\b -> F--A-b). */
|
|
4
|
+
export const projectFolderName = (workspace) => workspace.replace(/[^a-zA-Z0-9]/g, '-');
|
|
5
|
+
/**
|
|
6
|
+
* Every path the guest may know its workspace by, the real one first: a mirrored F:\A\b is a subst drive onto
|
|
7
|
+
* C:\Mirror\F\A\b, and programs that resolve real paths (realpath, GetFinalPathNameByHandle) report that one.
|
|
8
|
+
*/
|
|
9
|
+
export const guestWorkspaceAliases = (guestWorkspace) => {
|
|
10
|
+
const real = sandboxFolder(guestWorkspace);
|
|
11
|
+
return real.toLowerCase() === guestWorkspace.toLowerCase() ? [guestWorkspace] : [real, guestWorkspace];
|
|
12
|
+
};
|
|
13
|
+
const DEVICE_NAME = /^(con|prn|aux|nul|conin\$|conout\$|com[0-9¹²³]|lpt[0-9¹²³])(\..*)?$/i;
|
|
14
|
+
/**
|
|
15
|
+
* A file or folder name that is safe to recreate on this PC. The sandbox can create names Windows would treat as devices
|
|
16
|
+
* (CON.jsonl opens the console), as streams (a:b), or that end in a dot or space (silently renamed); none of them are copied.
|
|
17
|
+
*/
|
|
18
|
+
export const isSafeFileName = (name) => name !== '' && name.length <= 200 && name !== '.' && name !== '..' && !/[<>:"|?*/\\\x00-\x1f]/.test(name) && !/[. ]$/.test(name) && !DEVICE_NAME.test(name);
|
|
19
|
+
const jsonEscaped = (p) => JSON.stringify(p).slice(1, -1);
|
|
20
|
+
const escapeRegex = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
21
|
+
const forward = (p) => p.replace(/\\/g, '/');
|
|
22
|
+
/** Rewrites `from` to `to` wherever it appears as a whole path (raw, JSON-escaped or with forward slashes). */
|
|
23
|
+
export const translatePaths = (text, from, to) => {
|
|
24
|
+
if (from.toLowerCase() === to.toLowerCase())
|
|
25
|
+
return text;
|
|
26
|
+
const pairs = [[jsonEscaped(from), jsonEscaped(to)], [from, to], [forward(from), forward(to)]];
|
|
27
|
+
return pairs.reduce((out, [a, b]) => out.replace(new RegExp(escapeRegex(a) + '(?=\\\\|/|"|\'|\\s|$)', 'gi'), b.replace(/\$/g, '$$$$')), text);
|
|
28
|
+
};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/** Where roots, boot-mapped projects and shared folders appear inside the sandbox. */
|
|
2
|
+
export declare const PROJECTS_GUEST = "C:\\Projects";
|
|
3
|
+
/** How a project got into the sandbox. */
|
|
4
|
+
export type Mechanism = 'launch' | 'root' | 'boot' | 'wsb';
|
|
5
|
+
/** One project the running sandbox works on. */
|
|
6
|
+
export interface ProjectEntry {
|
|
7
|
+
name: string;
|
|
8
|
+
host: string;
|
|
9
|
+
guest: string;
|
|
10
|
+
primary: boolean;
|
|
11
|
+
mechanism: Mechanism;
|
|
12
|
+
}
|
|
13
|
+
/** `child` is `parent` or somewhere below it (Windows paths, case-insensitive). */
|
|
14
|
+
export declare const isWithin: (parent: string, child: string) => boolean;
|
|
15
|
+
/**
|
|
16
|
+
* A project id (also its folder name under C:\Projects) for a folder: its name with only letters, digits, '-' and
|
|
17
|
+
* '_' (ids become file names on both sides), at most 48 characters, made unique against `taken` with -2, -3, ...
|
|
18
|
+
*/
|
|
19
|
+
export declare const hubName: (hostDir: string, taken: Iterable<string>) => string;
|
|
20
|
+
/** The project a folder on this PC belongs to: the most specific one that contains it (a project inside another wins). */
|
|
21
|
+
export declare const projectForHostDir: <P extends {
|
|
22
|
+
host: string;
|
|
23
|
+
}>(projects: P[], hostDir: string) => P | null;
|
|
24
|
+
/** The same for a folder inside the sandbox. */
|
|
25
|
+
export declare const projectForGuestDir: <P extends {
|
|
26
|
+
guest: string;
|
|
27
|
+
}>(projects: P[], guestDir: string) => P | null;
|
|
28
|
+
/** Where a folder on this PC appears inside the sandbox, given the mapped folder (project or root) that contains it. */
|
|
29
|
+
export declare const guestDirFor: (mapped: {
|
|
30
|
+
host: string;
|
|
31
|
+
guest: string;
|
|
32
|
+
}, hostDir: string) => string;
|
|
33
|
+
/** The other way: where a folder inside the sandbox is on this PC, given the mapped folder that contains it. */
|
|
34
|
+
export declare const hostDirFor: (mapped: {
|
|
35
|
+
host: string;
|
|
36
|
+
guest: string;
|
|
37
|
+
}, guestDir: string) => string;
|
|
38
|
+
/** Strictly below `parent` (never `parent` itself). */
|
|
39
|
+
export declare const isBelow: (parent: string, child: string) => boolean;
|
|
40
|
+
/** A guest folder some project can be in: below C:\Projects, or inside one of the roots (their guest paths). */
|
|
41
|
+
export declare const insideProjects: (guestDir: string, roots?: string[], projectsDir?: string) => boolean;
|
|
42
|
+
export interface RootMapping {
|
|
43
|
+
host: string;
|
|
44
|
+
guest: string;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Guest folders for the project roots and the projects mapped at boot: C:\Projects\<name>, unique; with
|
|
48
|
+
* guestWorkspace "mirror" a root appears at its PC path when the sandbox can show it there.
|
|
49
|
+
*/
|
|
50
|
+
export declare const planProjectMappings: (roots: string[], projects: string[], mirror: boolean, taken?: string[]) => {
|
|
51
|
+
roots: RootMapping[];
|
|
52
|
+
projects: RootMapping[];
|
|
53
|
+
};
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
// Several projects in one running sandbox. Windows Sandbox fixes its mapped folders at boot, so a project can only
|
|
2
|
+
// join a running sandbox when it is already visible inside:
|
|
3
|
+
// - the launch folder (mapped directly, as always);
|
|
4
|
+
// - a folder inside a project root (projects.roots: whole folders of projects, mapped at every start), including
|
|
5
|
+
// projects created after boot;
|
|
6
|
+
// - projects mapped at boot because they were in use when the sandbox was restarted to add them;
|
|
7
|
+
// - a folder shared into the running sandbox with `wsb share` (Windows 11 24H2+, untested).
|
|
8
|
+
// Roots, boot-mapped projects and shares appear under C:\Projects (roots at their PC path with guestWorkspace "mirror").
|
|
9
|
+
// Pure functions only: used by the host (registration, commands), the guest (daemon checks) and the tests.
|
|
10
|
+
import path from 'node:path';
|
|
11
|
+
import { isValidGuestPath } from './guest-paths.js';
|
|
12
|
+
/** Where roots, boot-mapped projects and shared folders appear inside the sandbox. */
|
|
13
|
+
export const PROJECTS_GUEST = 'C:\\Projects';
|
|
14
|
+
const norm = (p) => path.win32.resolve(p).replace(/[\\/]+$/, '').toLowerCase();
|
|
15
|
+
/** `child` is `parent` or somewhere below it (Windows paths, case-insensitive). */
|
|
16
|
+
export const isWithin = (parent, child) => {
|
|
17
|
+
const a = norm(parent);
|
|
18
|
+
const b = norm(child);
|
|
19
|
+
return a === b || b.startsWith(a.endsWith('\\') ? a : a + '\\');
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* A project id (also its folder name under C:\Projects) for a folder: its name with only letters, digits, '-' and
|
|
23
|
+
* '_' (ids become file names on both sides), at most 48 characters, made unique against `taken` with -2, -3, ...
|
|
24
|
+
*/
|
|
25
|
+
export const hubName = (hostDir, taken) => {
|
|
26
|
+
const base = path.win32.basename(path.win32.resolve(hostDir)).replace(/[^A-Za-z0-9_-]+/g, '-').replace(/^-+|-+$/g, '').slice(0, 48) || 'project';
|
|
27
|
+
const used = new Set([...taken].map((t) => t.toLowerCase()));
|
|
28
|
+
if (!used.has(base.toLowerCase()))
|
|
29
|
+
return base;
|
|
30
|
+
for (let i = 2;; i++)
|
|
31
|
+
if (!used.has((base + '-' + i).toLowerCase()))
|
|
32
|
+
return base + '-' + i;
|
|
33
|
+
};
|
|
34
|
+
/** The project a folder on this PC belongs to: the most specific one that contains it (a project inside another wins). */
|
|
35
|
+
export const projectForHostDir = (projects, hostDir) => projects.filter((p) => isWithin(p.host, hostDir)).sort((a, b) => b.host.length - a.host.length)[0] ?? null;
|
|
36
|
+
/** The same for a folder inside the sandbox. */
|
|
37
|
+
export const projectForGuestDir = (projects, guestDir) => projects.filter((p) => isWithin(p.guest, guestDir)).sort((a, b) => b.guest.length - a.guest.length)[0] ?? null;
|
|
38
|
+
/** Where a folder on this PC appears inside the sandbox, given the mapped folder (project or root) that contains it. */
|
|
39
|
+
export const guestDirFor = (mapped, hostDir) => {
|
|
40
|
+
const rel = path.win32.relative(path.win32.resolve(mapped.host), path.win32.resolve(hostDir));
|
|
41
|
+
return rel ? path.win32.join(mapped.guest, rel) : mapped.guest;
|
|
42
|
+
};
|
|
43
|
+
/** The other way: where a folder inside the sandbox is on this PC, given the mapped folder that contains it. */
|
|
44
|
+
export const hostDirFor = (mapped, guestDir) => {
|
|
45
|
+
const rel = path.win32.relative(path.win32.resolve(mapped.guest), path.win32.resolve(guestDir));
|
|
46
|
+
return rel ? path.win32.join(mapped.host, rel) : mapped.host;
|
|
47
|
+
};
|
|
48
|
+
/** Strictly below `parent` (never `parent` itself). */
|
|
49
|
+
export const isBelow = (parent, child) => isWithin(parent, child) && norm(parent) !== norm(child);
|
|
50
|
+
/** A guest folder some project can be in: below C:\Projects, or inside one of the roots (their guest paths). */
|
|
51
|
+
export const insideProjects = (guestDir, roots = [], projectsDir = PROJECTS_GUEST) => isBelow(projectsDir, guestDir) || roots.some((r) => isWithin(r, guestDir));
|
|
52
|
+
/**
|
|
53
|
+
* Guest folders for the project roots and the projects mapped at boot: C:\Projects\<name>, unique; with
|
|
54
|
+
* guestWorkspace "mirror" a root appears at its PC path when the sandbox can show it there.
|
|
55
|
+
*/
|
|
56
|
+
export const planProjectMappings = (roots, projects, mirror, taken = []) => {
|
|
57
|
+
const names = [...taken];
|
|
58
|
+
const place = (host, tryMirror) => {
|
|
59
|
+
const resolved = path.win32.resolve(host).replace(/[\\/]+$/, '');
|
|
60
|
+
if (tryMirror && isValidGuestPath(resolved) && !isWithin(PROJECTS_GUEST, resolved))
|
|
61
|
+
return { host: resolved, guest: resolved };
|
|
62
|
+
const name = hubName(resolved, names);
|
|
63
|
+
names.push(name);
|
|
64
|
+
return { host: resolved, guest: path.win32.join(PROJECTS_GUEST, name) };
|
|
65
|
+
};
|
|
66
|
+
return { roots: roots.map((r) => place(r, mirror)), projects: projects.map((p) => place(p, false)) };
|
|
67
|
+
};
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import net from 'node:net';
|
|
2
|
+
export declare const FrameType: {
|
|
3
|
+
readonly Hello: 1;
|
|
4
|
+
readonly Input: 2;
|
|
5
|
+
readonly Resize: 3;
|
|
6
|
+
readonly Restart: 4;
|
|
7
|
+
readonly Ping: 5;
|
|
8
|
+
readonly Output: 16;
|
|
9
|
+
readonly Exit: 17;
|
|
10
|
+
readonly Error: 18;
|
|
11
|
+
readonly Restarting: 19;
|
|
12
|
+
readonly Status: 20;
|
|
13
|
+
};
|
|
14
|
+
/** HELLO flags: control-only connections get no output and never size the console; a query only asks for STATUS. */
|
|
15
|
+
export declare const HelloFlag: {
|
|
16
|
+
readonly ControlOnly: 1;
|
|
17
|
+
readonly Query: 2;
|
|
18
|
+
};
|
|
19
|
+
/** Viewers ping this often; ptyhost counts a viewer as gone after 15 s of silence (e.g. its terminal tab was closed). */
|
|
20
|
+
export declare const PING_INTERVAL_MS = 5000;
|
|
21
|
+
export interface Frame {
|
|
22
|
+
type: number;
|
|
23
|
+
payload: Buffer;
|
|
24
|
+
}
|
|
25
|
+
export interface Endpoint {
|
|
26
|
+
addresses: string[];
|
|
27
|
+
port: number;
|
|
28
|
+
token: string;
|
|
29
|
+
}
|
|
30
|
+
export type ClientResult = {
|
|
31
|
+
reason: 'exit';
|
|
32
|
+
exitCode: number;
|
|
33
|
+
} | {
|
|
34
|
+
reason: 'detach' | 'closed';
|
|
35
|
+
} | {
|
|
36
|
+
reason: 'error';
|
|
37
|
+
message: string;
|
|
38
|
+
};
|
|
39
|
+
/** Ctrl+] — the same detach key telnet uses; Claude Code does not bind it. */
|
|
40
|
+
export declare const DETACH_KEY = 29;
|
|
41
|
+
export declare const encodeFrame: (type: number, payload?: Buffer) => Buffer;
|
|
42
|
+
export declare const helloFrame: (token: string, cols: number, rows: number, flags?: number) => Buffer;
|
|
43
|
+
export declare const resizeFrame: (cols: number, rows: number) => Buffer;
|
|
44
|
+
/** Same limit as ptyhost.cs; a peer announcing more is broken or hostile. */
|
|
45
|
+
export declare const MAX_FRAME_BYTES: number;
|
|
46
|
+
/** Splits a TCP byte stream back into frames. */
|
|
47
|
+
export declare class FrameReader {
|
|
48
|
+
private pending;
|
|
49
|
+
push(chunk: Buffer): Frame[];
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Removes OSC 52 (clipboard write) from the sandbox's output before it reaches your terminal: an untrusted program
|
|
53
|
+
* must not be able to silently put text into your clipboard. Everything else (colours, titles, links) passes.
|
|
54
|
+
* Stateful, so a sequence split across chunks is still caught.
|
|
55
|
+
*/
|
|
56
|
+
export declare class OutputFilter {
|
|
57
|
+
private carry;
|
|
58
|
+
push(chunk: Buffer): Buffer;
|
|
59
|
+
}
|
|
60
|
+
/** Tries every address the sandbox published and returns the first one that answers. */
|
|
61
|
+
export declare const connect: (endpoint: Endpoint, timeoutMs?: number) => Promise<net.Socket>;
|
|
62
|
+
/** Sends one control frame (e.g. RESTART) without taking over the screen. */
|
|
63
|
+
export declare const sendControl: (endpoint: Endpoint, type: number) => Promise<void>;
|
|
64
|
+
/** Who is watching a session right now: `remote` counts viewers on the PC (not the sandbox's own tabs). */
|
|
65
|
+
export interface Viewers {
|
|
66
|
+
viewers: number;
|
|
67
|
+
remote: number;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Asks a session's ptyhost who is attached. Only viewers heard from in the last few seconds count, so a terminal that
|
|
71
|
+
* was closed (or a PC that went to sleep) is not reported. null when the session does not answer: an older ptyhost
|
|
72
|
+
* treats the query as a silent control connection, so the caller must not assume anything.
|
|
73
|
+
*/
|
|
74
|
+
export declare const queryViewers: (endpoint: Endpoint, timeoutMs?: number) => Promise<Viewers | null>;
|
|
75
|
+
/**
|
|
76
|
+
* Node on Windows reads keys through the console API, where Backspace is ^H and Ctrl+Backspace is DEL: the reverse of
|
|
77
|
+
* what terminals send. ConPTY reads ^H as Ctrl+Backspace (delete a word), so swap them back.
|
|
78
|
+
*/
|
|
79
|
+
export declare const fixWindowsKeys: (chunk: Buffer) => Buffer;
|
|
80
|
+
/**
|
|
81
|
+
* Bridges this process's terminal to the remote program until it exits, the connection drops, or the user presses
|
|
82
|
+
* the detach key. Restores the terminal before resolving.
|
|
83
|
+
*/
|
|
84
|
+
export declare const runTerminalClient: (socket: net.Socket, token: string, options?: {
|
|
85
|
+
detachKey?: number;
|
|
86
|
+
}) => Promise<ClientResult>;
|