windows-development-sandbox 1.0.5 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +25 -8
- package/config.example.json +55 -5
- package/dist/api.js +2 -1
- package/dist/cli/args.d.ts +23 -0
- package/dist/cli/args.js +38 -4
- package/dist/cli/colors.d.ts +24 -0
- package/dist/cli/colors.js +42 -0
- package/dist/cli/commands/accounts.js +2 -2
- 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 +2 -0
- package/dist/cli/commands/context.js +5 -1
- package/dist/cli/commands/data/clean.d.ts +15 -0
- package/dist/cli/commands/data/clean.js +106 -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 +6 -4
- package/dist/cli/commands/index.js +6 -4
- package/dist/cli/commands/launch.d.ts +26 -2
- package/dist/cli/commands/launch.js +256 -42
- package/dist/cli/commands/maintenance.d.ts +2 -0
- package/dist/cli/commands/maintenance.js +67 -5
- 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.js → repair/checks.js} +19 -181
- package/dist/cli/commands/{repair.d.ts → repair/finders.d.ts} +0 -29
- 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 +2 -1
- package/dist/cli/commands/sessions.js +189 -45
- package/dist/cli/commands/setup/checks.d.ts +13 -0
- package/dist/cli/commands/setup/checks.js +71 -0
- package/dist/cli/commands/{setup.d.ts → setup/facts.d.ts} +1 -15
- 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 +7 -1
- package/dist/cli/index.js +42 -15
- package/dist/cli/manifest.d.ts +8 -0
- package/dist/cli/manifest.js +40 -15
- package/dist/cli/menu/apps.d.ts +21 -0
- package/dist/cli/menu/apps.js +122 -0
- package/dist/cli/menu/command-form.d.ts +28 -0
- package/dist/cli/menu/command-form.js +219 -0
- package/dist/cli/menu/index.d.ts +26 -0
- package/dist/cli/menu/index.js +180 -0
- package/dist/cli/menu/settings/categories.d.ts +9 -0
- package/dist/cli/menu/settings/categories.js +28 -0
- package/dist/cli/menu/settings/config-file.d.ts +40 -0
- package/dist/cli/menu/settings/config-file.js +71 -0
- package/dist/cli/menu/settings/editors.d.ts +30 -0
- package/dist/cli/menu/settings/editors.js +305 -0
- package/dist/cli/menu/settings/index.d.ts +32 -0
- package/dist/cli/menu/settings/index.js +136 -0
- package/dist/cli/menu/settings/schema-node.d.ts +62 -0
- package/dist/cli/menu/settings/schema-node.js +104 -0
- package/dist/cli/menu/several.d.ts +20 -0
- package/dist/cli/menu/several.js +102 -0
- package/dist/cli/progress.d.ts +9 -0
- package/dist/cli/progress.js +49 -0
- package/dist/cli/tui/app.d.ts +39 -0
- package/dist/cli/tui/app.js +52 -0
- package/dist/cli/tui/dialogs.d.ts +57 -0
- package/dist/cli/tui/dialogs.js +162 -0
- package/dist/cli/tui/frame.d.ts +18 -0
- package/dist/cli/tui/frame.js +27 -0
- package/dist/cli/tui/index.d.ts +7 -0
- package/dist/cli/tui/index.js +8 -0
- package/dist/cli/tui/list-screen.d.ts +101 -0
- package/dist/cli/tui/list-screen.js +299 -0
- package/dist/cli/tui/terminal.d.ts +37 -0
- package/dist/cli/tui/terminal.js +89 -0
- package/dist/cli/tui/text.d.ts +20 -0
- package/dist/cli/tui/text.js +105 -0
- package/dist/cli/tui/theme.d.ts +45 -0
- package/dist/cli/tui/theme.js +30 -0
- package/dist/cli/validate.d.ts +17 -0
- package/dist/cli/validate.js +89 -0
- package/dist/core/config.js +12 -6
- package/dist/core/disk.d.ts +16 -0
- package/dist/core/disk.js +55 -0
- package/dist/core/local-config.d.ts +23 -0
- package/dist/core/local-config.js +79 -7
- 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/apps.d.ts +40 -0
- package/dist/core/schema/apps.js +27 -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 +659 -0
- package/dist/core/schema/config.js +75 -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 +32 -0
- package/dist/core/schema/profile.js +31 -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 +78 -0
- package/dist/core/schema/sandbox.js +64 -0
- package/dist/core/schema/toolchains.d.ts +96 -0
- package/dist/core/schema/toolchains.js +88 -0
- package/dist/core/schema.d.ts +6 -604
- package/dist/core/schema.js +8 -264
- package/dist/core/types.d.ts +35 -1
- package/dist/core/util.d.ts +9 -0
- package/dist/core/util.js +14 -3
- package/dist/core/workspace.d.ts +0 -5
- package/dist/core/workspace.js +33 -50
- package/dist/guest/apps/index.d.ts +10 -0
- package/dist/guest/apps/index.js +206 -0
- package/dist/guest/apps/resolvers.d.ts +8 -0
- package/dist/guest/apps/resolvers.js +90 -0
- package/dist/guest/audit-parse.d.ts +7 -0
- package/dist/guest/audit-parse.js +24 -0
- package/dist/guest/audit.d.ts +4 -0
- package/dist/guest/audit.js +47 -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/relays.d.ts +1 -0
- package/dist/guest/daemon/relays.js +18 -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.js +12 -141
- package/dist/guest/db.js +18 -3
- package/dist/guest/env.d.ts +3 -0
- package/dist/guest/env.js +7 -3
- package/dist/guest/guide.d.ts +6 -2
- package/dist/guest/guide.js +5 -4
- package/dist/guest/helpers.d.ts +3 -0
- package/dist/guest/helpers.js +26 -0
- package/dist/guest/main.js +31 -8
- package/dist/guest/netproxy.d.ts +1 -0
- package/dist/guest/netproxy.js +100 -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 +0 -18
- package/dist/guest/ptyhost.js +17 -65
- package/dist/guest/setup/agents.d.ts +5 -2
- package/dist/guest/setup/agents.js +22 -8
- package/dist/guest/setup/claude.d.ts +0 -4
- package/dist/guest/setup/claude.js +59 -5
- package/dist/guest/setup/environment.d.ts +13 -3
- package/dist/guest/setup/environment.js +14 -10
- package/dist/guest/setup/hooks.d.ts +9 -1
- package/dist/guest/setup/hooks.js +28 -14
- package/dist/guest/setup/network.d.ts +9 -0
- package/dist/guest/setup/network.js +97 -4
- package/dist/guest/setup/user.js +4 -0
- package/dist/guest/toolchains/catalogue.d.ts +4 -0
- package/dist/guest/toolchains/catalogue.js +2 -2
- package/dist/guest/toolchains/cli.js +25 -17
- package/dist/guest/toolchains/common.d.ts +18 -1
- package/dist/guest/toolchains/common.js +34 -11
- package/dist/guest/toolchains/databases/dynamodb.d.ts +8 -0
- package/dist/guest/toolchains/databases/dynamodb.js +52 -0
- package/dist/guest/toolchains/{databases.d.ts → databases/index.d.ts} +2 -3
- 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.js +25 -16
- package/dist/guest/toolchains/go.js +1 -1
- package/dist/guest/toolchains/index.d.ts +13 -9
- package/dist/guest/toolchains/index.js +40 -82
- package/dist/guest/toolchains/java.js +5 -5
- package/dist/guest/toolchains/leftovers.d.ts +2 -0
- package/dist/guest/toolchains/leftovers.js +26 -0
- package/dist/guest/toolchains/managers.js +12 -10
- package/dist/guest/toolchains/{binstall.js → native/binstall.js} +6 -9
- 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 +56 -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.js +26 -6
- package/dist/guest/toolchains/plan.d.ts +24 -0
- package/dist/guest/toolchains/plan.js +140 -0
- package/dist/guest/toolchains/pwsh.js +1 -1
- package/dist/guest/toolchains/python.js +43 -12
- package/dist/guest/toolchains/runtimes.d.ts +2 -0
- package/dist/guest/toolchains/runtimes.js +6 -8
- 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/vscode-profile.d.ts +30 -0
- package/dist/guest/toolchains/vscode-profile.js +69 -0
- package/dist/guest/toolchains/vscode.d.ts +17 -0
- package/dist/guest/toolchains/vscode.js +87 -1
- package/dist/guest/view.js +21 -1
- package/dist/host/accounts.js +14 -5
- 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 +70 -0
- package/dist/host/audit/collect.d.ts +34 -0
- package/dist/host/audit/collect.js +126 -0
- package/dist/host/audit/log.d.ts +46 -0
- package/dist/host/audit/log.js +143 -0
- package/dist/host/channel.d.ts +23 -22
- package/dist/host/channel.js +66 -84
- package/dist/host/claude-profile.js +7 -3
- package/dist/host/cleanup.js +2 -11
- package/dist/host/database-plan.d.ts +12 -0
- package/dist/host/database-plan.js +52 -0
- package/dist/host/generate.d.ts +10 -12
- package/dist/host/generate.js +58 -135
- 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 +54 -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/motw.d.ts +17 -0
- package/dist/host/motw.js +74 -0
- package/dist/host/pc-scan.d.ts +6 -0
- package/dist/host/pc-scan.js +37 -0
- package/dist/host/platform.d.ts +2 -0
- package/dist/host/platform.js +16 -1
- package/dist/host/port-forward.d.ts +8 -0
- package/dist/host/port-forward.js +37 -0
- package/dist/host/project-scan.d.ts +1 -17
- package/dist/host/project-scan.js +2 -86
- package/dist/host/projects.d.ts +100 -0
- package/dist/host/projects.js +147 -0
- package/dist/host/repo-guard.d.ts +25 -5
- package/dist/host/repo-guard.js +242 -23
- package/dist/host/stops.d.ts +67 -0
- package/dist/host/stops.js +126 -0
- package/dist/host/terminal.d.ts +8 -0
- package/dist/host/terminal.js +48 -1
- package/dist/host/test-guard.d.ts +6 -0
- package/dist/host/test-guard.js +15 -0
- package/dist/host/window.js +7 -3
- package/dist/host/workspace-view/index.d.ts +20 -0
- package/dist/host/workspace-view/index.js +53 -0
- package/dist/host/workspace-view/rules.d.ts +26 -0
- package/dist/host/workspace-view/rules.js +93 -0
- package/dist/host/workspace-view/view.d.ts +50 -0
- package/dist/host/workspace-view/view.js +281 -0
- package/dist/host/wsb.d.ts +37 -0
- package/dist/host/wsb.js +101 -0
- package/dist/runtime/daemon.js +11791 -2821
- package/dist/runtime/db.js +6585 -466
- package/dist/runtime/main.js +10238 -1724
- package/dist/runtime/netproxy.js +25936 -0
- package/dist/runtime/view.js +6183 -59
- 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/audit.test.d.ts +2 -0
- package/dist/selftest/audit.test.js +57 -0
- package/dist/selftest/channel.test.d.ts +2 -0
- package/dist/selftest/channel.test.js +44 -0
- package/dist/selftest/cli.test.d.ts +2 -2
- package/dist/selftest/cli.test.js +145 -27
- 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 -3
- package/dist/selftest/config.test.js +36 -72
- package/dist/selftest/data.test.d.ts +2 -2
- package/dist/selftest/data.test.js +77 -70
- package/dist/selftest/detect.test.d.ts +2 -2
- package/dist/selftest/detect.test.js +54 -38
- package/dist/selftest/fixtures.d.ts +89 -4
- package/dist/selftest/fixtures.js +43 -24
- package/dist/selftest/generate.test.d.ts +2 -0
- package/dist/selftest/generate.test.js +68 -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 +44 -7
- package/dist/selftest/harness.js +62 -21
- 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 -1
- package/dist/selftest/index.js +137 -35
- 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-network.test.d.ts +2 -0
- package/dist/selftest/live-network.test.js +63 -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 +120 -0
- package/dist/selftest/mirror.test.d.ts +2 -3
- package/dist/selftest/mirror.test.js +92 -65
- package/dist/selftest/network.test.d.ts +2 -0
- package/dist/selftest/network.test.js +40 -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 +121 -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 -2
- package/dist/selftest/setup.test.js +45 -22
- package/dist/selftest/suite.d.ts +13 -0
- package/dist/selftest/suite.js +1 -0
- package/dist/selftest/sync.test.d.ts +2 -3
- package/dist/selftest/sync.test.js +130 -78
- 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 +133 -0
- package/dist/selftest/workspace-view.test.d.ts +2 -0
- package/dist/selftest/workspace-view.test.js +89 -0
- package/dist/selftest/workspace.test.d.ts +2 -0
- package/dist/selftest/workspace.test.js +53 -0
- package/dist/shared/apps.d.ts +49 -0
- package/dist/shared/apps.js +114 -0
- package/dist/shared/download.d.ts +3 -1
- package/dist/shared/download.js +19 -4
- package/dist/shared/netpolicy.d.ts +27 -0
- package/dist/shared/netpolicy.js +51 -0
- package/dist/shared/paths.d.ts +5 -0
- package/dist/shared/paths.js +6 -0
- package/dist/shared/projects.d.ts +53 -0
- package/dist/shared/projects.js +67 -0
- package/dist/shared/pty-client.d.ts +9 -4
- package/dist/shared/pty-client.js +139 -17
- package/dist/shared/rundir.d.ts +12 -1
- package/dist/shared/rundir.js +14 -4
- package/dist/shared/safe-remove.js +11 -0
- package/dist/shared/schema.d.ts +453 -0
- package/dist/shared/schema.js +43 -2
- package/dist/shared/system.d.ts +1 -0
- package/dist/shared/system.js +1 -0
- package/dist/shared/test-guard.d.ts +4 -0
- package/dist/shared/test-guard.js +37 -0
- package/dist/sync/claude-mem.js +6 -3
- package/dist/sync/history.d.ts +29 -12
- package/dist/sync/history.js +72 -25
- package/dist/sync/watcher.d.ts +8 -0
- package/dist/sync/watcher.js +99 -8
- package/package.json +7 -6
- package/sandbox/bootstrap.ps1 +258 -258
- package/sandbox/cargoshim.cs +56 -0
- package/sandbox/cpucap.cs +33 -0
- package/sandbox/cpucap.ps1 +20 -0
- package/sandbox/logon.cmd +24 -16
- package/sandbox/memlog.ps1 +34 -0
- package/sandbox/openssl.cs +42 -0
- package/sandbox/pagefile.cs +31 -0
- package/sandbox/pagefile.ps1 +21 -0
- package/sandbox/ptyhost.cs +120 -11
- package/sandbox/trust.cmd +35 -35
- package/schemas/config.schema.json +403 -3
- package/schemas/sandbox-config.schema.json +143 -13
- package/dist/cli/commands/data.d.ts +0 -46
- package/dist/cli/commands/data.js +0 -249
- package/dist/cli/commands/setup.js +0 -152
- package/dist/cli/menu.d.ts +0 -22
- package/dist/cli/menu.js +0 -187
- package/dist/cli/settings.d.ts +0 -11
- package/dist/cli/settings.js +0 -156
- package/dist/guest/toolchains/databases.js +0 -226
- package/dist/guest/toolchains/msvc.d.ts +0 -10
- package/dist/guest/toolchains/msvc.js +0 -216
- package/dist/guest/toolchains/native.d.ts +0 -12
- package/dist/guest/toolchains/native.js +0 -220
- package/dist/guest/toolchains/scripting.d.ts +0 -10
- package/dist/guest/toolchains/scripting.js +0 -137
- package/dist/selftest/guest.test.d.ts +0 -3
- package/dist/selftest/guest.test.js +0 -61
- package/dist/selftest/helpers.test.d.ts +0 -2
- package/dist/selftest/helpers.test.js +0 -125
- package/dist/selftest/host.test.d.ts +0 -2
- package/dist/selftest/host.test.js +0 -71
- package/dist/selftest/live.test.d.ts +0 -7
- package/dist/selftest/live.test.js +0 -127
- package/dist/selftest/security.test.d.ts +0 -3
- package/dist/selftest/security.test.js +0 -143
- /package/dist/guest/toolchains/{binstall.d.ts → native/binstall.d.ts} +0 -0
package/dist/host/generate.js
CHANGED
|
@@ -1,160 +1,77 @@
|
|
|
1
|
+
// Writes a launch folder for one sandbox: session.json (what the guest needs to know), the bundled runtime, hooks, the
|
|
2
|
+
// staged Claude settings and the .wsb file that starts Windows Sandbox. The pieces live in launch/.
|
|
1
3
|
import fs from 'node:fs';
|
|
2
|
-
import os from 'node:os';
|
|
3
4
|
import path from 'node:path';
|
|
4
5
|
import crypto from 'node:crypto';
|
|
5
|
-
import { assertNoGuestOverlap, userDir } from '../core/config.js';
|
|
6
|
-
import { capturePersonalization } from './personalize.js';
|
|
7
|
-
import { assertSafeMapping } from '../core/workspace.js';
|
|
8
|
-
import { isValidGuestPath, MIRROR_ROOT, sandboxFolder, substDrives } from '../shared/guest-paths.js';
|
|
9
|
-
import { hostClaudeDir, stageClaudeProfile } from './claude-profile.js';
|
|
10
6
|
import { decideToolchains, resolveToolchains } from '../core/detect-toolchains.js';
|
|
11
|
-
import { databaseCatalog, msvcHint, pcLanguages, planDatabases, projectEntries } from './project-scan.js';
|
|
12
7
|
import { readPwshScripts, usesPwsh } from '../core/detect-pwsh.js';
|
|
13
|
-
import { dirExists, ensureDir, fail,
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
+ '<ClipboardRedirection>' + toggle(s.clipboard) + '</ClipboardRedirection>'
|
|
35
|
-
+ '<AudioInput>' + toggle(s.audioInput) + '</AudioInput>'
|
|
36
|
-
+ '<VideoInput>' + toggle(s.videoInput) + '</VideoInput>'
|
|
37
|
-
+ '<PrinterRedirection>' + toggle(s.printerRedirection) + '</PrinterRedirection>'
|
|
38
|
-
+ '<ProtectedClient>' + toggle(s.protectedClient) + '</ProtectedClient>'
|
|
39
|
-
+ '<MappedFolders>' + folders + '</MappedFolders>'
|
|
40
|
-
+ '<LogonCommand><Command>' + xmlEscape(GUEST.launch + '\\sandbox\\logon.cmd') + '</Command></LogonCommand>'
|
|
41
|
-
+ '</Configuration>';
|
|
42
|
-
};
|
|
43
|
-
const collectMappings = (o, launchPath) => {
|
|
44
|
-
const { config, dataPath, workspaceHost, harnessName } = o.run;
|
|
45
|
-
assertGuestPath(config.guestWorkspace, 'guestWorkspace');
|
|
46
|
-
const mappings = [
|
|
47
|
-
{ host: launchPath, guest: GUEST.launch, readOnly: true },
|
|
48
|
-
{ host: dataPath, guest: GUEST.data, readOnly: false },
|
|
49
|
-
{ host: workspaceHost, guest: config.guestWorkspace, readOnly: config.readOnly },
|
|
50
|
-
];
|
|
51
|
-
for (const m of config.mappings) {
|
|
52
|
-
const host = m.host;
|
|
53
|
-
assertGuestPath(m.guest, 'mappings[].guest for ' + host);
|
|
54
|
-
if (!dirExists(host)) {
|
|
55
|
-
if (m.optional) {
|
|
56
|
-
console.warn('Skipping optional mapping (folder not found): ' + host);
|
|
57
|
-
continue;
|
|
58
|
-
}
|
|
59
|
-
fail('A mapped folder does not exist: ' + host, 'Create it, fix the path in your config, or mark the mapping "optional": true.');
|
|
60
|
-
}
|
|
61
|
-
assertSafeMapping(host, o.packageRoot, o.run.storageRoot);
|
|
62
|
-
mappings.push({ host, guest: m.guest, readOnly: m.readOnly });
|
|
63
|
-
}
|
|
64
|
-
const { probe } = o;
|
|
65
|
-
if (probe.nodeDir)
|
|
66
|
-
mappings.push({ host: probe.nodeDir, guest: GUEST.hostTools + '\\node', readOnly: true });
|
|
67
|
-
if (probe.harnessExe && harnessName !== 'none')
|
|
68
|
-
mappings.push({ host: probe.harnessExe.dir, guest: GUEST.hostTools + '\\agents\\' + harnessName, readOnly: true });
|
|
69
|
-
if (probe.gitDir)
|
|
70
|
-
mappings.push({ host: probe.gitDir, guest: GUEST.hostTools + '\\git', readOnly: true });
|
|
71
|
-
if (probe.nvmDir)
|
|
72
|
-
mappings.push({ host: probe.nvmDir, guest: GUEST.hostTools + '\\nvm', readOnly: true });
|
|
73
|
-
assertNoGuestOverlap(mappings);
|
|
74
|
-
// Same check on where the folders really are (F:\x and C:\Mirror\F\x are one place).
|
|
75
|
-
assertNoGuestOverlap(mappings.map((m) => ({ guest: sandboxFolder(m.guest) })));
|
|
76
|
-
return mappings;
|
|
77
|
-
};
|
|
78
|
-
/** The schema checks this already; the host re-checks what goes into the .wsb and the subst list anyway. */
|
|
79
|
-
const assertGuestPath = (guest, what) => {
|
|
80
|
-
if (!isValidGuestPath(guest))
|
|
81
|
-
fail(what + ' is not a usable sandbox folder: ' + guest, 'Use a folder under C:\\ (not Windows, Program Files, Users, AgentData, Mirror, ...) or on drive D: to Z:, e.g. C:\\Assets or F:\\SteamLibrary\\steamapps\\common\\Game.');
|
|
82
|
-
};
|
|
83
|
-
/** Package hooks first, then ~/.agent-sandbox/hooks (same file name = user's wins), then --script / "scripts". */
|
|
84
|
-
const stageHooks = (packageRoot, launchPath, scripts) => {
|
|
85
|
-
for (const stage of HOOK_STAGES) {
|
|
86
|
-
const target = path.join(launchPath, 'hooks', stage);
|
|
87
|
-
ensureDir(target);
|
|
88
|
-
for (const source of [path.join(packageRoot, 'hooks', stage), path.join(userDir(), 'hooks', stage)]) {
|
|
89
|
-
if (dirExists(source))
|
|
90
|
-
fs.cpSync(source, target, { recursive: true, force: true });
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
scripts.forEach((script, index) => {
|
|
94
|
-
if (!fileExists(script))
|
|
95
|
-
fail('Script file not found: ' + script, 'Check the --script path.');
|
|
96
|
-
fs.copyFileSync(script, path.join(launchPath, 'hooks', 'pre-agent', '90-extra-' + index + '-' + path.basename(script)));
|
|
97
|
-
});
|
|
98
|
-
};
|
|
99
|
-
export const RUNTIME_FILES = ['main.js', 'daemon.js', 'view.js', 'gitguard.js', 'db.js'];
|
|
100
|
-
/** The bundled sandbox runtime (dist/runtime: one self-contained file per entry point) and the sandbox/ scripts. */
|
|
101
|
-
const copyRuntime = (packageRoot, launchPath) => {
|
|
102
|
-
const runtime = path.join(packageRoot, 'dist', 'runtime');
|
|
103
|
-
const missing = RUNTIME_FILES.filter((f) => !fileExists(path.join(runtime, f)));
|
|
104
|
-
if (missing.length)
|
|
105
|
-
fail('The sandbox runtime is missing from ' + runtime + ' (' + missing.join(', ') + ').', 'Rebuild it: npm run build (or reinstall the package).');
|
|
106
|
-
ensureDir(path.join(launchPath, 'runtime'));
|
|
107
|
-
for (const file of RUNTIME_FILES)
|
|
108
|
-
fs.copyFileSync(path.join(runtime, file), path.join(launchPath, 'runtime', file));
|
|
109
|
-
fs.writeFileSync(path.join(launchPath, 'package.json'), '{ "type": "module" }\n', 'utf8');
|
|
110
|
-
fs.cpSync(path.join(packageRoot, 'sandbox'), path.join(launchPath, 'sandbox'), { recursive: true });
|
|
111
|
-
};
|
|
112
|
-
/** Only the identity from ~/.gitconfig: the rest can hold credentials (helpers, tokens in insteadOf URLs). */
|
|
113
|
-
export const gitIdentity = (gitconfig) => {
|
|
114
|
-
const values = {};
|
|
115
|
-
let section = '';
|
|
116
|
-
for (const line of gitconfig.split(/\r?\n/)) {
|
|
117
|
-
const header = /^\s*\[([^\]]+)\]/.exec(line);
|
|
118
|
-
if (header) {
|
|
119
|
-
section = header[1].trim().toLowerCase();
|
|
120
|
-
continue;
|
|
121
|
-
}
|
|
122
|
-
const pair = /^\s*(name|email)\s*=\s*(.*?)\s*$/i.exec(line);
|
|
123
|
-
if (section === 'user' && pair && !/[\r\n]/.test(pair[2]))
|
|
124
|
-
values[pair[1].toLowerCase()] = pair[2].replace(/^"(.*)"$/, '$1');
|
|
125
|
-
}
|
|
126
|
-
const lines = Object.entries(values).map(([k, v]) => '\t' + k + ' = ' + v);
|
|
127
|
-
return lines.length ? '[user]\n' + lines.join('\n') + '\n' : '';
|
|
8
|
+
import { dirExists, ensureDir, fail, writeJson } from '../core/util.js';
|
|
9
|
+
import { substDrives } from '../shared/guest-paths.js';
|
|
10
|
+
import { PROJECTS_GUEST, hubName } from '../shared/projects.js';
|
|
11
|
+
import { planBootProjects } from './launch/projects.js';
|
|
12
|
+
import { hostClaudeDir, stageClaudeProfile } from './claude-profile.js';
|
|
13
|
+
import { databaseCatalog, planDatabases } from './database-plan.js';
|
|
14
|
+
import { collectMappings } from './launch/mappings.js';
|
|
15
|
+
import { copyRuntime, stageGitIdentity, stageHooks } from './launch/stage.js';
|
|
16
|
+
import { buildWsb, resolveMemoryMb } from './launch/wsb.js';
|
|
17
|
+
import { capturePersonalization } from './personalize.js';
|
|
18
|
+
import { pcLanguages } from './pc-scan.js';
|
|
19
|
+
import { msvcHint, projectEntries } from './project-scan.js';
|
|
20
|
+
import { assertTestWritable } from './test-guard.js';
|
|
21
|
+
const NO_PROFILE = { hostDir: null, staged: [], skipped: [], credentials: false, secretsRemoved: [] };
|
|
22
|
+
/** Which toolchains the project needs ("auto" settings follow the project's files and what this PC has). */
|
|
23
|
+
export const decideProjectToolchains = (o) => {
|
|
24
|
+
const { config, workspaceHost } = o.run;
|
|
25
|
+
const msvcScript = config.toolchains.msvc.enabled === 'auto' ? msvcHint(workspaceHost) : undefined;
|
|
26
|
+
const pwshScript = config.toolchains.pwsh.enabled === 'auto' ? usesPwsh(readPwshScripts(workspaceHost)) : null;
|
|
27
|
+
const hints = { ...(msvcScript ? { msvc: msvcScript } : {}), ...(pwshScript ? { pwsh: pwshScript } : {}) };
|
|
28
|
+
return decideToolchains(config.toolchains, projectEntries(workspaceHost), o.pcLanguages ?? pcLanguages(), hints);
|
|
128
29
|
};
|
|
30
|
+
/** What was found on this PC to copy instead of download. */
|
|
31
|
+
const hostToolsOf = (probe) => ({
|
|
32
|
+
node: Boolean(probe.nodeDir),
|
|
33
|
+
nodeVersion: probe.nodeDir || probe.nvmNode ? probe.hostNodeVersion.replace(/^v/, '') : null,
|
|
34
|
+
harnessExecutable: probe.harnessExe?.file ?? null,
|
|
35
|
+
git: Boolean(probe.gitDir),
|
|
36
|
+
nvm: Boolean(probe.nvmDir),
|
|
37
|
+
volta: Boolean(probe.volta),
|
|
38
|
+
pyenv: Boolean(probe.pyenv),
|
|
39
|
+
});
|
|
40
|
+
/**
|
|
41
|
+
* env.cmd, which logon.cmd calls before it opens Windows Terminal: Terminal expands "%AGENT_WORKSPACE%" (the starting
|
|
42
|
+
* folder of new tabs) from its own environment, and the runtime only sets the variable machine-wide after Terminal
|
|
43
|
+
* started. `%` is doubled for cmd; a Windows path holds no quotes.
|
|
44
|
+
*/
|
|
45
|
+
export const logonEnv = (workspace) => '@set "AGENT_WORKSPACE=' + workspace.replace(/[\r\n"]/g, '').replace(/%/g, '%%') + '"\r\n';
|
|
129
46
|
export const generateSandbox = (o) => {
|
|
130
47
|
const { config, dataPath, workspaceHost, harnessName, storageRoot } = o.run;
|
|
131
48
|
const harness = harnessName === 'none' ? null : config.harnesses[harnessName] ?? fail('Unknown agent: ' + harnessName, 'Configured agents: ' + Object.keys(config.harnesses).join(', '));
|
|
132
49
|
if (!dirExists(workspaceHost))
|
|
133
50
|
fail('The workspace folder does not exist: ' + workspaceHost, 'cd into the project first.');
|
|
51
|
+
assertTestWritable(storageRoot);
|
|
52
|
+
assertTestWritable(dataPath);
|
|
134
53
|
// Checked before anything is written, so a refusal leaves nothing behind.
|
|
135
54
|
const memoryMb = resolveMemoryMb(config.sandbox, o.freeMemoryBytes);
|
|
136
55
|
const launchId = Date.now() + '-' + crypto.randomBytes(3).toString('hex');
|
|
137
56
|
const launchPath = path.join(storageRoot, 'launches', launchId);
|
|
138
57
|
ensureDir(launchPath);
|
|
139
58
|
ensureDir(dataPath);
|
|
140
|
-
const
|
|
141
|
-
const
|
|
142
|
-
const
|
|
143
|
-
|
|
144
|
-
if (identity) {
|
|
145
|
-
ensureDir(path.join(launchPath, 'home'));
|
|
146
|
-
fs.writeFileSync(path.join(launchPath, 'home', '.gitconfig'), identity, 'utf8');
|
|
147
|
-
}
|
|
59
|
+
const boot = planBootProjects({ run: o.run, packageRoot: o.packageRoot, extraProjects: o.extraProjects, knownProjects: o.knownProjects });
|
|
60
|
+
const mappings = collectMappings(o, launchPath, boot);
|
|
61
|
+
const profile = harnessName === 'claude' ? stageClaudeProfile(config.claudeProfile, launchPath, workspaceHost, config.secrets) : NO_PROFILE;
|
|
62
|
+
stageGitIdentity(launchPath);
|
|
148
63
|
const personalization = config.personalization.enabled ? capturePersonalization(launchPath) : 'disabled';
|
|
149
64
|
const databases = o.databases ?? planDatabases(config.databases, workspaceHost);
|
|
150
|
-
const
|
|
151
|
-
const pwshScript = config.toolchains.pwsh.enabled === 'auto' ? usesPwsh(readPwshScripts(workspaceHost)) : null;
|
|
152
|
-
const toolchainDecisions = decideToolchains(config.toolchains, projectEntries(workspaceHost), o.pcLanguages ?? pcLanguages(), { ...(msvcScript ? { msvc: msvcScript } : {}), ...(pwshScript ? { pwsh: pwshScript } : {}) });
|
|
65
|
+
const toolchainDecisions = decideProjectToolchains(o);
|
|
153
66
|
const session = {
|
|
154
67
|
launchId,
|
|
155
68
|
project: path.basename(workspaceHost),
|
|
69
|
+
projectId: hubName(workspaceHost, []),
|
|
156
70
|
workspace: config.guestWorkspace,
|
|
157
71
|
workspaceHost,
|
|
72
|
+
projectsDir: PROJECTS_GUEST,
|
|
73
|
+
roots: boot.roots.map((r) => r.guest),
|
|
74
|
+
...(o.autoSession === false ? { autoSession: false } : {}),
|
|
158
75
|
harnessName,
|
|
159
76
|
harness,
|
|
160
77
|
harnessArguments: o.harnessArgs,
|
|
@@ -170,16 +87,22 @@ export const generateSandbox = (o) => {
|
|
|
170
87
|
versions: o.run.versions,
|
|
171
88
|
attach: config.attach,
|
|
172
89
|
hooks: config.hooks,
|
|
173
|
-
|
|
90
|
+
downloads: config.downloads,
|
|
91
|
+
hostTools: hostToolsOf(o.probe),
|
|
174
92
|
claudeProfile: { overwrite: config.claudeProfile.overwrite, items: profile.staged, credentials: profile.credentials, hostConfigDir: profile.hostDir ?? hostClaudeDir(config.claudeProfile), syncClaudeMem: config.claudeProfile.syncClaudeMem },
|
|
175
93
|
personalization: fs.existsSync(path.join(launchPath, 'personalize', 'personalize.reg')),
|
|
176
94
|
substDrives: substDrives(mappings.map((m) => m.guest)),
|
|
95
|
+
cpuLimitPercent: config.sandbox.cpuLimit === 'none' ? null : config.sandbox.cpuLimit,
|
|
96
|
+
pageFileMb: config.sandbox.pageFileMb,
|
|
97
|
+
apps: config.apps,
|
|
98
|
+
auditProcesses: config.audit.enabled && config.audit.processes,
|
|
177
99
|
};
|
|
178
100
|
const sessionPath = path.join(launchPath, 'session.json');
|
|
179
101
|
writeJson(sessionPath, session);
|
|
102
|
+
fs.writeFileSync(path.join(launchPath, 'env.cmd'), logonEnv(session.workspace), 'utf8');
|
|
180
103
|
copyRuntime(o.packageRoot, launchPath);
|
|
181
104
|
stageHooks(o.packageRoot, launchPath, o.run.scripts);
|
|
182
105
|
const wsbPath = path.join(launchPath, 'agent.wsb');
|
|
183
106
|
fs.writeFileSync(wsbPath, buildWsb(config, memoryMb, mappings), 'utf8');
|
|
184
|
-
return { wsbPath, launchPath, launchId, sessionPath, memoryMb, mappings, profile, personalization, databases, toolchains: toolchainDecisions };
|
|
107
|
+
return { wsbPath, launchPath, launchId, sessionPath, memoryMb, mappings, profile, personalization, databases, toolchains: toolchainDecisions, projects: boot };
|
|
185
108
|
};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { ResolvedRun } from '../core/types.js';
|
|
2
|
+
import { type ProjectSpecT } from '../shared/schema.js';
|
|
3
|
+
import { type ProjectMapper, type RegistryEntry } from './projects.js';
|
|
4
|
+
/** The launch folder of the running sandbox (host-only storage; its id comes from the guest, so it is checked). */
|
|
5
|
+
export declare const runningLaunchPath: (storageRoot: string, dataPath: string) => string | null;
|
|
6
|
+
/** What a session or command from this folder needs: where it is inside, and (for another project) its spec. */
|
|
7
|
+
export interface Joined {
|
|
8
|
+
project: RegistryEntry;
|
|
9
|
+
guestDir: string;
|
|
10
|
+
spec: ProjectSpecT | null;
|
|
11
|
+
run: ResolvedRun | null;
|
|
12
|
+
notes: string[];
|
|
13
|
+
}
|
|
14
|
+
/** The project spec the guest provisions from (scans the project folder like a launch does). */
|
|
15
|
+
export declare const projectSpec: (run: ResolvedRun, entry: RegistryEntry, hooks: boolean) => ProjectSpecT;
|
|
16
|
+
/**
|
|
17
|
+
* Makes `hostDir` usable in the running sandbox. The launch folder (or a folder below it) needs nothing; any other
|
|
18
|
+
* folder is resolved with `resolve` (the caller's resolveRun, with the approval prompt), checked, and registered.
|
|
19
|
+
*/
|
|
20
|
+
export declare const joinRunning: (o: {
|
|
21
|
+
storageRoot: string;
|
|
22
|
+
dataPath: string;
|
|
23
|
+
packageRoot: string;
|
|
24
|
+
hostDir: string;
|
|
25
|
+
wsbShare: boolean;
|
|
26
|
+
resolve: (projectRoot: string) => Promise<ResolvedRun>;
|
|
27
|
+
mapper?: ProjectMapper;
|
|
28
|
+
}) => Promise<Joined>;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
// Joining the running sandbox from another folder. The folder's run is resolved exactly as a fresh launch would
|
|
2
|
+
// resolve it (its approved .sandbox-config.json, versions, toolchain detection, database plan), checked against the
|
|
3
|
+
// running sandbox's machine-wide protections, made visible inside (host/projects.ts: a project root, a project
|
|
4
|
+
// mapped at boot, or wsb share) and described to the guest, which provisions what is missing before its session.
|
|
5
|
+
// When none of those can make it visible, NeedsRestart reaches the caller, which offers a restart.
|
|
6
|
+
import fs from 'node:fs';
|
|
7
|
+
import path from 'node:path';
|
|
8
|
+
import { checkJoin, protectionsOf } from '../core/project-policy.js';
|
|
9
|
+
import { resolveToolchains } from '../core/detect-toolchains.js';
|
|
10
|
+
import { assertNoLinks, fail } from '../core/util.js';
|
|
11
|
+
import { Id } from '../shared/schema.js';
|
|
12
|
+
import { readSandboxStatus } from '../shared/rundir.js';
|
|
13
|
+
import { syncProjectIn } from '../sync/watcher.js';
|
|
14
|
+
import { planDatabases } from './database-plan.js';
|
|
15
|
+
import { decideProjectToolchains } from './generate.js';
|
|
16
|
+
import { projectHere, projectMapper, readRegistry, rememberProject, rootHere } from './projects.js';
|
|
17
|
+
import { stageScripts } from './launch/stage.js';
|
|
18
|
+
import { addRepoSnapshot } from './repo-guard.js';
|
|
19
|
+
/** The launch folder of the running sandbox (host-only storage; its id comes from the guest, so it is checked). */
|
|
20
|
+
export const runningLaunchPath = (storageRoot, dataPath) => {
|
|
21
|
+
const launchId = readSandboxStatus(dataPath)?.launchId;
|
|
22
|
+
if (!launchId || !/^\d+-[0-9a-f]{6}$/.test(launchId) || readRegistry(storageRoot)?.launchId !== launchId)
|
|
23
|
+
return null;
|
|
24
|
+
const launchPath = path.join(storageRoot, 'launches', launchId);
|
|
25
|
+
assertNoLinks(storageRoot, launchPath);
|
|
26
|
+
return fs.existsSync(path.join(launchPath, 'session.json')) ? launchPath : null;
|
|
27
|
+
};
|
|
28
|
+
/** The project spec the guest provisions from (scans the project folder like a launch does). */
|
|
29
|
+
export const projectSpec = (run, entry, hooks) => {
|
|
30
|
+
const { config } = run;
|
|
31
|
+
const toolchains = resolveToolchains(config.toolchains, decideProjectToolchains({ run }));
|
|
32
|
+
const harness = run.harnessName === 'none' ? null : config.harnesses[run.harnessName];
|
|
33
|
+
return {
|
|
34
|
+
name: Id.parse(entry.name), workspace: entry.guest, workspaceHost: entry.host, toolchains, versions: run.versions,
|
|
35
|
+
databases: planDatabases(config.databases, run.workspaceHost).slice(0, 8),
|
|
36
|
+
harnesses: harness ? { [run.harnessName]: harness } : {},
|
|
37
|
+
hooks,
|
|
38
|
+
};
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* Makes `hostDir` usable in the running sandbox. The launch folder (or a folder below it) needs nothing; any other
|
|
42
|
+
* folder is resolved with `resolve` (the caller's resolveRun, with the approval prompt), checked, and registered.
|
|
43
|
+
*/
|
|
44
|
+
export const joinRunning = async (o) => {
|
|
45
|
+
const here = projectHere(o.storageRoot, o.hostDir);
|
|
46
|
+
if (here?.project.primary)
|
|
47
|
+
return { ...here, spec: null, run: null, notes: [] };
|
|
48
|
+
const registry = readRegistry(o.storageRoot) ?? fail('The running sandbox was started by an older version, so it cannot take another folder.', 'Stop it (sandbox stop) and start it again.');
|
|
49
|
+
// A folder below a project already in the sandbox uses that project; anything else becomes a project of its own.
|
|
50
|
+
const root = here?.project.host ?? path.resolve(o.hostDir);
|
|
51
|
+
const run = await o.resolve(root);
|
|
52
|
+
const check = checkJoin(registry.protections, protectionsOf(run.config));
|
|
53
|
+
if (check.stricter.length) {
|
|
54
|
+
fail('This project needs stricter protection than the running sandbox has, and those settings are machine-wide:\n ' + check.stricter.join('\n '), 'Its sessions cannot get them without changing them for the sessions already running. Stop the sandbox (sandbox stop) and start it from ' + root + '.');
|
|
55
|
+
}
|
|
56
|
+
const mapper = o.mapper ?? projectMapper({ storageRoot: o.storageRoot, packageRoot: o.packageRoot, wsbShare: o.wsbShare });
|
|
57
|
+
// Guarded from now on. A folder the sandbox could already write (inside a root, or mapped at boot) and that has no
|
|
58
|
+
// snapshot from the launch gets an empty one: what is there now may have been planted, so it counts as new.
|
|
59
|
+
// Anything else is snapshotted before it becomes visible.
|
|
60
|
+
addRepoSnapshot(o.dataPath, root, { empty: Boolean(here) || Boolean(rootHere(o.storageRoot, root)) });
|
|
61
|
+
const entry = mapper.register(root);
|
|
62
|
+
rememberProject(o.storageRoot, entry.host);
|
|
63
|
+
const launchPath = runningLaunchPath(o.storageRoot, o.dataPath);
|
|
64
|
+
// Your hooks in ~/.agent-sandbox/hooks ran at boot (once per sandbox); the project's own scripts ("scripts" in its
|
|
65
|
+
// .sandbox-config.json, --script) run before its first agent. The launch folder is read-only for the sandbox, but
|
|
66
|
+
// this side can still add them to it.
|
|
67
|
+
const hooks = Boolean(launchPath) && run.scripts.length > 0;
|
|
68
|
+
if (launchPath && hooks)
|
|
69
|
+
stageScripts(path.join(launchPath, 'projects', entry.name, 'hooks', 'pre-agent'), run.scripts);
|
|
70
|
+
try {
|
|
71
|
+
syncProjectIn(o.dataPath, { hostWorkspace: entry.host, guestWorkspace: entry.guest });
|
|
72
|
+
}
|
|
73
|
+
catch { /* history is a convenience; never block the session */ }
|
|
74
|
+
const notes = [...run.notes, ...check.looser.map((l) => 'The running sandbox is stricter: ' + l + '.')];
|
|
75
|
+
return { project: entry, guestDir: here ? here.guestDir : entry.guest, spec: projectSpec(run, entry, hooks), run, notes };
|
|
76
|
+
};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { assertNoGuestOverlap } from '../../core/config.js';
|
|
2
|
+
import { assertSafeMapping } from '../../core/safe-paths.js';
|
|
3
|
+
import { dirExists, fail } from '../../core/util.js';
|
|
4
|
+
import { isValidGuestPath, sandboxFolder } from '../../shared/guest-paths.js';
|
|
5
|
+
import { GUEST } from './wsb.js';
|
|
6
|
+
import { guestGitDir, planView } from '../workspace-view/index.js';
|
|
7
|
+
export const collectMappings = (o, launchPath, boot = { roots: [], projects: [], notes: [] }) => {
|
|
8
|
+
const { config, dataPath, workspaceHost, harnessName } = o.run;
|
|
9
|
+
assertGuestPath(config.guestWorkspace, 'guestWorkspace');
|
|
10
|
+
// workspaceFilter: the sandbox gets the project's filtered view (no git-ignored files) and its real .git beside it.
|
|
11
|
+
const view = planView(config, o.run.storageRoot, workspaceHost);
|
|
12
|
+
const mappings = [
|
|
13
|
+
{ host: launchPath, guest: GUEST.launch, readOnly: true },
|
|
14
|
+
{ host: dataPath, guest: GUEST.data, readOnly: false },
|
|
15
|
+
{ host: view ? view.options.view : workspaceHost, guest: config.guestWorkspace, readOnly: config.readOnly },
|
|
16
|
+
...(view?.hostGit ? [{ host: view.hostGit, guest: guestGitDir(config.guestWorkspace), readOnly: config.readOnly }] : []),
|
|
17
|
+
];
|
|
18
|
+
for (const m of config.mappings) {
|
|
19
|
+
const host = m.host;
|
|
20
|
+
assertGuestPath(m.guest, 'mappings[].guest for ' + host);
|
|
21
|
+
if (!dirExists(host)) {
|
|
22
|
+
if (m.optional) {
|
|
23
|
+
console.warn('Skipping optional mapping (folder not found): ' + host);
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
fail('A mapped folder does not exist: ' + host, 'Create it, fix the path in your config, or mark the mapping "optional": true.');
|
|
27
|
+
}
|
|
28
|
+
assertSafeMapping(host, o.packageRoot, o.run.storageRoot);
|
|
29
|
+
mappings.push({ host, guest: m.guest, readOnly: m.readOnly });
|
|
30
|
+
}
|
|
31
|
+
// Project roots and other projects, so they can join the running sandbox without a restart (launch/projects.ts).
|
|
32
|
+
for (const m of [...boot.roots, ...boot.projects]) {
|
|
33
|
+
assertGuestPath(m.guest, 'project folder for ' + m.host);
|
|
34
|
+
mappings.push({ host: m.host, guest: m.guest, readOnly: false });
|
|
35
|
+
}
|
|
36
|
+
const { probe } = o;
|
|
37
|
+
if (probe.nodeDir)
|
|
38
|
+
mappings.push({ host: probe.nodeDir, guest: GUEST.hostTools + '\\node', readOnly: true });
|
|
39
|
+
if (probe.harnessExe && harnessName !== 'none')
|
|
40
|
+
mappings.push({ host: probe.harnessExe.dir, guest: GUEST.hostTools + '\\agents\\' + harnessName, readOnly: true });
|
|
41
|
+
if (probe.gitDir)
|
|
42
|
+
mappings.push({ host: probe.gitDir, guest: GUEST.hostTools + '\\git', readOnly: true });
|
|
43
|
+
if (probe.nvmDir)
|
|
44
|
+
mappings.push({ host: probe.nvmDir, guest: GUEST.hostTools + '\\nvm', readOnly: true });
|
|
45
|
+
assertNoGuestOverlap(mappings);
|
|
46
|
+
// Same check on where the folders really are (F:\x and C:\Mirror\F\x are one place).
|
|
47
|
+
assertNoGuestOverlap(mappings.map((m) => ({ guest: sandboxFolder(m.guest) })));
|
|
48
|
+
return mappings;
|
|
49
|
+
};
|
|
50
|
+
/** The schema checks this already; the host re-checks what goes into the .wsb and the subst list anyway. */
|
|
51
|
+
const assertGuestPath = (guest, what) => {
|
|
52
|
+
if (!isValidGuestPath(guest))
|
|
53
|
+
fail(what + ' is not a usable sandbox folder: ' + guest, 'Use a folder under C:\\ (not Windows, Program Files, Users, AgentData, Mirror, ...) or on drive D: to Z:, e.g. C:\\Assets or F:\\SteamLibrary\\steamapps\\common\\Game.');
|
|
54
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { ResolvedRun } from '../../core/types.js';
|
|
2
|
+
import { type RootMapping } from '../../shared/projects.js';
|
|
3
|
+
/** More folders than this would make the .wsb (and every boot) unwieldy; the rest join with a restart later. */
|
|
4
|
+
export declare const MAX_BOOT_PROJECTS = 48;
|
|
5
|
+
export interface BootProjects {
|
|
6
|
+
roots: RootMapping[];
|
|
7
|
+
projects: RootMapping[];
|
|
8
|
+
notes: string[];
|
|
9
|
+
}
|
|
10
|
+
export declare const planBootProjects: (o: {
|
|
11
|
+
run: ResolvedRun;
|
|
12
|
+
packageRoot: string;
|
|
13
|
+
extraProjects?: string[];
|
|
14
|
+
knownProjects?: string[];
|
|
15
|
+
}) => BootProjects;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
// Which folders besides the launch folder are mapped so other projects can join without a restart: the project
|
|
2
|
+
// roots (projects.roots), projects carried over by a restart that added one, and with projects.all every project
|
|
3
|
+
// started before (except projects.exclude). Every one passes the same checks as a launch folder.
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import { assertSafeMapping, assertSafeWorkspace } from '../../core/safe-paths.js';
|
|
6
|
+
import { dirExists, errMsg, fail } from '../../core/util.js';
|
|
7
|
+
import { isWithin, planProjectMappings } from '../../shared/projects.js';
|
|
8
|
+
import { allProjectsToMap, readKnown } from '../projects.js';
|
|
9
|
+
/** More folders than this would make the .wsb (and every boot) unwieldy; the rest join with a restart later. */
|
|
10
|
+
export const MAX_BOOT_PROJECTS = 48;
|
|
11
|
+
export const planBootProjects = (o) => {
|
|
12
|
+
const { config, workspaceHost, storageRoot } = o.run;
|
|
13
|
+
const notes = [];
|
|
14
|
+
const safe = (folder) => {
|
|
15
|
+
try {
|
|
16
|
+
assertSafeWorkspace(folder, o.packageRoot, storageRoot);
|
|
17
|
+
assertSafeMapping(folder, o.packageRoot, storageRoot);
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
catch (e) {
|
|
21
|
+
return errMsg(e);
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
const roots = [];
|
|
25
|
+
for (const root of config.projects.roots.map((r) => path.resolve(r))) {
|
|
26
|
+
if (!dirExists(root)) {
|
|
27
|
+
notes.push('Project root not found, skipped: ' + root);
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
const refusal = safe(root);
|
|
31
|
+
if (refusal)
|
|
32
|
+
fail('projects.roots: ' + refusal, 'Use a folder that holds your projects, e.g. F:\\Code (not a drive, your profile or a system folder).');
|
|
33
|
+
if (!roots.some((r) => isWithin(r, root)))
|
|
34
|
+
roots.push(root);
|
|
35
|
+
}
|
|
36
|
+
const known = o.knownProjects ?? readKnown(storageRoot).map((k) => k.host);
|
|
37
|
+
const wanted = [...(o.extraProjects ?? []), ...(config.projects.all ? allProjectsToMap(known, { primary: workspaceHost, roots, exclude: config.projects.exclude }) : [])];
|
|
38
|
+
const projects = [];
|
|
39
|
+
for (const folder of wanted.map((p) => path.resolve(p))) {
|
|
40
|
+
if (isWithin(workspaceHost, folder) || roots.some((r) => isWithin(r, folder)) || projects.some((p) => isWithin(p, folder) || isWithin(folder, p)))
|
|
41
|
+
continue;
|
|
42
|
+
if (!dirExists(folder))
|
|
43
|
+
continue;
|
|
44
|
+
const refusal = safe(folder);
|
|
45
|
+
if (refusal) {
|
|
46
|
+
notes.push('Not mapped: ' + refusal);
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
if (projects.length >= MAX_BOOT_PROJECTS) {
|
|
50
|
+
notes.push('More than ' + MAX_BOOT_PROJECTS + ' projects: the rest are not mapped (a project root holds any number).');
|
|
51
|
+
break;
|
|
52
|
+
}
|
|
53
|
+
projects.push(folder);
|
|
54
|
+
}
|
|
55
|
+
return { ...planProjectMappings(roots, projects, Boolean(o.run.mirror)), notes };
|
|
56
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/** Package hooks first, then ~/.agent-sandbox/hooks (same file name = user's wins), then --script / "scripts". */
|
|
2
|
+
export declare const stageHooks: (packageRoot: string, launchPath: string, scripts: string[]) => void;
|
|
3
|
+
/** --script / "scripts" files, run before the agent in this order. */
|
|
4
|
+
export declare const stageScripts: (target: string, scripts: string[]) => void;
|
|
5
|
+
export declare const RUNTIME_FILES: string[];
|
|
6
|
+
/** The bundled sandbox runtime (dist/runtime: one self-contained file per entry point) and the sandbox/ scripts. */
|
|
7
|
+
export declare const copyRuntime: (packageRoot: string, launchPath: string) => void;
|
|
8
|
+
/** Only the identity from ~/.gitconfig: the rest can hold credentials (helpers, tokens in insteadOf URLs). */
|
|
9
|
+
export declare const gitIdentity: (gitconfig: string) => string;
|
|
10
|
+
/** Writes this PC's git name and email to home\.gitconfig in the launch folder (nothing when there are none). */
|
|
11
|
+
export declare const stageGitIdentity: (launchPath: string) => void;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
// What is copied into the launch folder (C:\AgentLaunch inside the sandbox): hooks, the bundled runtime, the git identity.
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { userDir } from '../../core/config.js';
|
|
5
|
+
import { dirExists, ensureDir, fail, fileExists, homeDir } from '../../core/util.js';
|
|
6
|
+
const HOOK_STAGES = ['pre-provision', 'pre-agent', 'post-agent'];
|
|
7
|
+
/** Package hooks first, then ~/.agent-sandbox/hooks (same file name = user's wins), then --script / "scripts". */
|
|
8
|
+
export const stageHooks = (packageRoot, launchPath, scripts) => {
|
|
9
|
+
for (const stage of HOOK_STAGES) {
|
|
10
|
+
const target = path.join(launchPath, 'hooks', stage);
|
|
11
|
+
ensureDir(target);
|
|
12
|
+
for (const source of [path.join(packageRoot, 'hooks', stage), path.join(userDir(), 'hooks', stage)]) {
|
|
13
|
+
if (dirExists(source))
|
|
14
|
+
fs.cpSync(source, target, { recursive: true, force: true });
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
stageScripts(path.join(launchPath, 'hooks', 'pre-agent'), scripts);
|
|
18
|
+
};
|
|
19
|
+
/** --script / "scripts" files, run before the agent in this order. */
|
|
20
|
+
export const stageScripts = (target, scripts) => {
|
|
21
|
+
ensureDir(target);
|
|
22
|
+
scripts.forEach((script, index) => {
|
|
23
|
+
if (!fileExists(script))
|
|
24
|
+
fail('Script file not found: ' + script, 'Check the --script path.');
|
|
25
|
+
fs.copyFileSync(script, path.join(target, '90-extra-' + index + '-' + path.basename(script)));
|
|
26
|
+
});
|
|
27
|
+
};
|
|
28
|
+
export const RUNTIME_FILES = ['main.js', 'daemon.js', 'view.js', 'gitguard.js', 'db.js', 'netproxy.js'];
|
|
29
|
+
/** The bundled sandbox runtime (dist/runtime: one self-contained file per entry point) and the sandbox/ scripts. */
|
|
30
|
+
export const copyRuntime = (packageRoot, launchPath) => {
|
|
31
|
+
const runtime = path.join(packageRoot, 'dist', 'runtime');
|
|
32
|
+
const missing = RUNTIME_FILES.filter((f) => !fileExists(path.join(runtime, f)));
|
|
33
|
+
if (missing.length)
|
|
34
|
+
fail('The sandbox runtime is missing from ' + runtime + ' (' + missing.join(', ') + ').', 'Rebuild it: npm run build (or reinstall the package).');
|
|
35
|
+
ensureDir(path.join(launchPath, 'runtime'));
|
|
36
|
+
for (const file of RUNTIME_FILES)
|
|
37
|
+
fs.copyFileSync(path.join(runtime, file), path.join(launchPath, 'runtime', file));
|
|
38
|
+
fs.writeFileSync(path.join(launchPath, 'package.json'), '{ "type": "module" }\n', 'utf8');
|
|
39
|
+
fs.cpSync(path.join(packageRoot, 'sandbox'), path.join(launchPath, 'sandbox'), { recursive: true });
|
|
40
|
+
};
|
|
41
|
+
/** Only the identity from ~/.gitconfig: the rest can hold credentials (helpers, tokens in insteadOf URLs). */
|
|
42
|
+
export const gitIdentity = (gitconfig) => {
|
|
43
|
+
const values = {};
|
|
44
|
+
let section = '';
|
|
45
|
+
for (const line of gitconfig.split(/\r?\n/)) {
|
|
46
|
+
const header = /^\s*\[([^\]]+)\]/.exec(line);
|
|
47
|
+
if (header) {
|
|
48
|
+
section = header[1].trim().toLowerCase();
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
const pair = /^\s*(name|email)\s*=\s*(.*?)\s*$/i.exec(line);
|
|
52
|
+
if (section === 'user' && pair && !/[\r\n]/.test(pair[2]))
|
|
53
|
+
values[pair[1].toLowerCase()] = pair[2].replace(/^"(.*)"$/, '$1');
|
|
54
|
+
}
|
|
55
|
+
const lines = Object.entries(values).map(([k, v]) => '\t' + k + ' = ' + v);
|
|
56
|
+
return lines.length ? '[user]\n' + lines.join('\n') + '\n' : '';
|
|
57
|
+
};
|
|
58
|
+
/** Writes this PC's git name and email to home\.gitconfig in the launch folder (nothing when there are none). */
|
|
59
|
+
export const stageGitIdentity = (launchPath) => {
|
|
60
|
+
const gitconfig = path.join(homeDir(), '.gitconfig');
|
|
61
|
+
const identity = fileExists(gitconfig) ? gitIdentity(fs.readFileSync(gitconfig, 'utf8')) : '';
|
|
62
|
+
if (!identity)
|
|
63
|
+
return;
|
|
64
|
+
ensureDir(path.join(launchPath, 'home'));
|
|
65
|
+
fs.writeFileSync(path.join(launchPath, 'home', '.gitconfig'), identity, 'utf8');
|
|
66
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Config, ResolvedMapping } from '../../core/types.js';
|
|
2
|
+
export declare const GUEST: {
|
|
3
|
+
readonly launch: "C:\\AgentLaunch";
|
|
4
|
+
readonly data: "C:\\AgentData";
|
|
5
|
+
readonly hostTools: "C:\\HostTools";
|
|
6
|
+
readonly mirror: "C:\\Mirror";
|
|
7
|
+
};
|
|
8
|
+
/** "auto": free RAM minus the reserve, but never more than maxMemoryMb or maxMemoryPercent of the PC's total RAM. */
|
|
9
|
+
export declare const resolveMemoryMb: (sandbox: Config["sandbox"], freeMemoryBytes?: number, totalMemoryBytes?: number) => number;
|
|
10
|
+
export declare const buildWsb: (config: Config, memoryMb: number, mappings: ResolvedMapping[]) => string;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// The .wsb file Windows Sandbox starts from: memory, devices and the folders mapped in.
|
|
2
|
+
import os from 'node:os';
|
|
3
|
+
import { fail, xmlEscape } from '../../core/util.js';
|
|
4
|
+
import { MIRROR_ROOT, sandboxFolder } from '../../shared/guest-paths.js';
|
|
5
|
+
export const GUEST = { launch: 'C:\\AgentLaunch', data: 'C:\\AgentData', hostTools: 'C:\\HostTools', mirror: MIRROR_ROOT };
|
|
6
|
+
const toggle = (value) => (value ? 'Enable' : 'Disable');
|
|
7
|
+
/** "auto": free RAM minus the reserve, but never more than maxMemoryMb or maxMemoryPercent of the PC's total RAM. */
|
|
8
|
+
export const resolveMemoryMb = (sandbox, freeMemoryBytes = os.freemem(), totalMemoryBytes = os.totalmem()) => {
|
|
9
|
+
if (sandbox.memoryMb !== 'auto')
|
|
10
|
+
return sandbox.memoryMb;
|
|
11
|
+
const freeMb = Math.floor(freeMemoryBytes / 1048576);
|
|
12
|
+
const shareMb = Math.floor((totalMemoryBytes / 1048576) * sandbox.maxMemoryPercent / 100);
|
|
13
|
+
const rounded = Math.floor(Math.min(sandbox.maxMemoryMb, shareMb, freeMb - sandbox.reserveHostMb) / 1024) * 1024;
|
|
14
|
+
if (rounded < 4096)
|
|
15
|
+
fail('Not enough free RAM for the sandbox (' + freeMb + ' MB free, ' + sandbox.reserveHostMb + ' MB kept for this PC).', 'Close some apps, lower sandbox.reserveHostMb, or set sandbox.memoryMb to a fixed value (>= 4096).');
|
|
16
|
+
return rounded;
|
|
17
|
+
};
|
|
18
|
+
export const buildWsb = (config, memoryMb, mappings) => {
|
|
19
|
+
const s = config.sandbox;
|
|
20
|
+
// Guest paths on other drive letters (F:\x) really live under C:\Mirror\F; bootstrap.ps1 substs F: onto it at boot.
|
|
21
|
+
const folders = mappings.map((m) => '<MappedFolder><HostFolder>' + xmlEscape(m.host) + '</HostFolder><SandboxFolder>' + xmlEscape(sandboxFolder(m.guest)) + '</SandboxFolder><ReadOnly>' + String(m.readOnly) + '</ReadOnly></MappedFolder>').join('');
|
|
22
|
+
return '<Configuration>'
|
|
23
|
+
+ '<MemoryInMB>' + memoryMb + '</MemoryInMB>'
|
|
24
|
+
+ '<vGPU>' + toggle(s.vGpu) + '</vGPU>'
|
|
25
|
+
+ '<Networking>' + toggle(s.networking) + '</Networking>'
|
|
26
|
+
+ '<ClipboardRedirection>' + toggle(s.clipboard) + '</ClipboardRedirection>'
|
|
27
|
+
+ '<AudioInput>' + toggle(s.audioInput) + '</AudioInput>'
|
|
28
|
+
+ '<VideoInput>' + toggle(s.videoInput) + '</VideoInput>'
|
|
29
|
+
+ '<PrinterRedirection>' + toggle(s.printerRedirection) + '</PrinterRedirection>'
|
|
30
|
+
+ '<ProtectedClient>' + toggle(s.protectedClient) + '</ProtectedClient>'
|
|
31
|
+
+ '<MappedFolders>' + folders + '</MappedFolders>'
|
|
32
|
+
+ '<LogonCommand><Command>' + xmlEscape(GUEST.launch + '\\sandbox\\logon.cmd') + '</Command></LogonCommand>'
|
|
33
|
+
+ '</Configuration>';
|
|
34
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/** What Windows runs when you open it (not source files such as .js or .py: those need a program you choose). */
|
|
2
|
+
export declare const RISKY: RegExp;
|
|
3
|
+
/** Marks one file if it is a program or script (and a plain file, not a link). Returns true when it marked it. */
|
|
4
|
+
export declare const markFromSandbox: (file: string) => boolean;
|
|
5
|
+
/** Has this file the mark? */
|
|
6
|
+
export declare const isMarked: (file: string) => boolean;
|
|
7
|
+
/** Watches the projects while the sandbox runs and marks what appears or changes; returns a function that stops it. */
|
|
8
|
+
export declare const watchAndMark: (projects: string[], note?: (message: string) => void) => (() => void);
|
|
9
|
+
/** The projects to watch and mark (empty: storage.markSandboxFiles is off). */
|
|
10
|
+
export declare const saveMarkedProjects: (storageRoot: string, dataPath: string, projects: string[]) => void;
|
|
11
|
+
export declare const readMarkedProjects: (storageRoot: string, dataPath: string) => string[];
|
|
12
|
+
/** The data folder's size, measured by the watcher when a sandbox closes (measuring at launch would be slow). */
|
|
13
|
+
export declare const saveDataSize: (storageRoot: string, dataPath: string, bytes: number) => void;
|
|
14
|
+
export declare const readDataSize: (storageRoot: string, dataPath: string) => {
|
|
15
|
+
bytes: number;
|
|
16
|
+
at: string;
|
|
17
|
+
} | null;
|