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
|
@@ -2,14 +2,15 @@
|
|
|
2
2
|
import fs from 'node:fs';
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
import { SYSTEM } from '../../shared/system.js';
|
|
5
|
-
import {
|
|
5
|
+
import { uvVars } from '../toolchains/runtimes.js';
|
|
6
|
+
import { dryRun, execAsync, exists, hostToolsDir, isWin, log, mkdirp, session, toolsDir, warn } from '../env.js';
|
|
6
7
|
const harnessPaths = (name, harness) => {
|
|
7
8
|
const dir = path.join(toolsDir, 'agents', name);
|
|
8
9
|
const exe = harness.hostExecutable ?? (harness.uvBin ? harness.uvBin + '.exe' : null);
|
|
9
10
|
return { dir, exe: exe ? path.join(dir, exe) : null, cmd: harness.npmBin ? path.join(dir, harness.npmBin + '.cmd') : null };
|
|
10
11
|
};
|
|
11
12
|
/** npm install with the runner's own npm into tools\agents\<name> (no global state outside persistent storage). */
|
|
12
|
-
const installViaNpm = (name, harness, dir, env) => {
|
|
13
|
+
const installViaNpm = async (name, harness, dir, env) => {
|
|
13
14
|
if (!harness.npmPackage)
|
|
14
15
|
throw new Error('No npmPackage configured for ' + name + ' and no host executable was available.');
|
|
15
16
|
const npmCli = path.join(path.dirname(process.execPath), 'node_modules', 'npm', 'bin', 'npm-cli.js');
|
|
@@ -21,10 +22,10 @@ const installViaNpm = (name, harness, dir, env) => {
|
|
|
21
22
|
}
|
|
22
23
|
if (!exists(npmCli))
|
|
23
24
|
throw new Error('npm not found at ' + npmCli);
|
|
24
|
-
|
|
25
|
+
await execAsync(process.execPath, args, { env });
|
|
25
26
|
};
|
|
26
27
|
/** `uv tool install` with its command put straight into tools\agents\<name> (Python agents such as aider). */
|
|
27
|
-
const installViaUv = (name, harness, dir, env) => {
|
|
28
|
+
const installViaUv = async (name, harness, dir, env) => {
|
|
28
29
|
const uv = path.join(toolsDir, 'uv', 'uv.exe');
|
|
29
30
|
log('Installing ' + harness.uvPackage + ' with uv (this can take a minute)...');
|
|
30
31
|
if (dryRun) {
|
|
@@ -33,10 +34,23 @@ const installViaUv = (name, harness, dir, env) => {
|
|
|
33
34
|
}
|
|
34
35
|
if (!exists(uv))
|
|
35
36
|
throw new Error(name + ' is installed with uv; enable toolchains.uv');
|
|
36
|
-
|
|
37
|
+
await execAsync(uv, ['tool', 'install', '--force', '--python', '3.12', harness.uvPackage], { env: { ...env, ...uvVars(), UV_TOOL_BIN_DIR: dir } });
|
|
37
38
|
};
|
|
38
|
-
/**
|
|
39
|
+
/** One install per agent at a time: two sessions asking for a new agent at once share the first one's install. */
|
|
40
|
+
const installing = new Map();
|
|
41
|
+
/**
|
|
42
|
+
* Copies the agent from this PC when it was mapped in (primary agent only), otherwise installs it with npm or uv.
|
|
43
|
+
* Asynchronous, so the session daemon keeps serving other requests while an agent installs.
|
|
44
|
+
*/
|
|
39
45
|
export const provisionHarness = (name, harness, env, refresh = session.provisioning.refresh) => {
|
|
46
|
+
const current = installing.get(name);
|
|
47
|
+
if (current)
|
|
48
|
+
return current;
|
|
49
|
+
const work = installHarness(name, harness, env, refresh).finally(() => installing.delete(name));
|
|
50
|
+
installing.set(name, work);
|
|
51
|
+
return work;
|
|
52
|
+
};
|
|
53
|
+
const installHarness = async (name, harness, env, refresh) => {
|
|
40
54
|
const p = harnessPaths(name, harness);
|
|
41
55
|
const cached = (p.exe !== null && exists(p.exe)) || (p.cmd !== null && exists(p.cmd));
|
|
42
56
|
if (cached && !refresh) {
|
|
@@ -56,9 +70,9 @@ export const provisionHarness = (name, harness, env, refresh = session.provision
|
|
|
56
70
|
warn('Host copy of ' + name + ' not available; installing instead.');
|
|
57
71
|
}
|
|
58
72
|
if (harness.uvPackage && !harness.npmPackage)
|
|
59
|
-
installViaUv(name, harness, p.dir, env);
|
|
73
|
+
await installViaUv(name, harness, p.dir, env);
|
|
60
74
|
else
|
|
61
|
-
installViaNpm(name, harness, p.dir, env);
|
|
75
|
+
await installViaNpm(name, harness, p.dir, env);
|
|
62
76
|
};
|
|
63
77
|
/** Program + arguments that start the agent (an npm .cmd shim has to go through cmd.exe). */
|
|
64
78
|
export const resolveLaunch = (name, harness) => {
|
|
@@ -14,8 +14,4 @@ export declare const claudeMemPaths: {
|
|
|
14
14
|
local: string;
|
|
15
15
|
};
|
|
16
16
|
export declare const restoreClaudeMem: () => void;
|
|
17
|
-
/**
|
|
18
|
-
* Copies the live claude-mem folder back to persistent storage (staging folder + swap, never a half copy). Called from
|
|
19
|
-
* the daemon tick: when no database changed since the last save it does nothing (no copy of the whole folder).
|
|
20
|
-
*/
|
|
21
17
|
export declare const saveClaudeMem: () => void;
|
|
@@ -3,6 +3,8 @@ import fs from 'node:fs';
|
|
|
3
3
|
import os from 'node:os';
|
|
4
4
|
import path from 'node:path';
|
|
5
5
|
import { translatePaths } from '../../shared/paths.js';
|
|
6
|
+
import { writeJsonAtomic } from '../../shared/rundir.js';
|
|
7
|
+
import { safeRemove } from '../../shared/safe-remove.js';
|
|
6
8
|
import { claudeDir, dryRun, exists, launchDir, log, mkdirp, robocopy, session, stateDir, warn, workspace } from '../env.js';
|
|
7
9
|
/** The sandbox keeps its own login and global state; everything else is refreshed from this PC each boot. */
|
|
8
10
|
const KEEP_SANDBOX_COPY = ['.claude.json', '.credentials.json'];
|
|
@@ -41,7 +43,7 @@ export const mergeMcpServers = (hostFile, guestFile, hostWorkspace, guestWorkspa
|
|
|
41
43
|
const guestKey = Object.keys(projects).find((key) => sameFolder(key, guestWorkspace)) ?? guestWorkspace.replace(/\\/g, '/');
|
|
42
44
|
projects[guestKey] = { ...(projects[guestKey] ?? {}), mcpServers: { ...(projects[guestKey]?.mcpServers ?? {}), ...hostProject } };
|
|
43
45
|
const merged = { ...guest, mcpServers: { ...(guest.mcpServers ?? {}), ...(host.mcpServers ?? {}) }, projects };
|
|
44
|
-
|
|
46
|
+
writeJsonAtomic(guestFile, merged);
|
|
45
47
|
return Object.keys(host.mcpServers ?? {}).length + Object.keys(hostProject).length;
|
|
46
48
|
};
|
|
47
49
|
export const syncClaudeProfile = () => {
|
|
@@ -63,7 +65,7 @@ export const syncClaudeProfile = () => {
|
|
|
63
65
|
}
|
|
64
66
|
// Folders (skills, commands, plugins) are mirrored: what was removed on this PC goes here too.
|
|
65
67
|
if (fs.statSync(from).isDirectory())
|
|
66
|
-
|
|
68
|
+
safeRemove(to, claudeDir);
|
|
67
69
|
fs.cpSync(from, to, { recursive: true, force: true });
|
|
68
70
|
log('Claude settings: copied ' + name + ' from this PC');
|
|
69
71
|
}
|
|
@@ -81,7 +83,24 @@ export const syncClaudeProfile = () => {
|
|
|
81
83
|
export const claudeMemPaths = { store: path.join(stateDir, 'claude-mem'), local: path.join(os.homedir(), '.claude-mem') };
|
|
82
84
|
const claudeMemEnabled = () => session.claudeProfile.syncClaudeMem && !dryRun;
|
|
83
85
|
export const restoreClaudeMem = () => {
|
|
84
|
-
if (!claudeMemEnabled()
|
|
86
|
+
if (!claudeMemEnabled())
|
|
87
|
+
return;
|
|
88
|
+
// A save cut off between its two renames (see saveClaudeMem) leaves only the aside copy: it is the newest data.
|
|
89
|
+
const previous = claudeMemPaths.store + '.previous';
|
|
90
|
+
if (!exists(claudeMemPaths.store) && exists(previous))
|
|
91
|
+
fs.renameSync(previous, claudeMemPaths.store);
|
|
92
|
+
// A store that is gone or damaged: the newest backup that is a real database.
|
|
93
|
+
const backups = claudeMemPaths.store + '.backups';
|
|
94
|
+
if (!looksLikeSqlite(path.join(claudeMemPaths.store, 'claude-mem.db')) || !exists(claudeMemPaths.store)) {
|
|
95
|
+
const good = (exists(backups) ? fs.readdirSync(backups).sort().reverse() : []).find((b) => exists(path.join(backups, b, 'claude-mem.db')) && looksLikeSqlite(path.join(backups, b, 'claude-mem.db')));
|
|
96
|
+
if (good) {
|
|
97
|
+
if (exists(claudeMemPaths.store))
|
|
98
|
+
fs.renameSync(claudeMemPaths.store, claudeMemPaths.store + '.damaged-' + Date.now());
|
|
99
|
+
fs.cpSync(path.join(backups, good), claudeMemPaths.store, { recursive: true });
|
|
100
|
+
warn('claude-mem: the stored database was missing or damaged; restored the backup from ' + new Date(Number(good)).toISOString() + '.');
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
if (!exists(claudeMemPaths.store))
|
|
85
104
|
return;
|
|
86
105
|
robocopy(claudeMemPaths.store, claudeMemPaths.local);
|
|
87
106
|
log('claude-mem data restored from persistent storage.');
|
|
@@ -109,6 +128,36 @@ let lastSaved = null;
|
|
|
109
128
|
* Copies the live claude-mem folder back to persistent storage (staging folder + swap, never a half copy). Called from
|
|
110
129
|
* the daemon tick: when no database changed since the last save it does nothing (no copy of the whole folder).
|
|
111
130
|
*/
|
|
131
|
+
const SQLITE_HEADER = 'SQLite format 3\0';
|
|
132
|
+
/** A database file that starts like SQLite and is not empty (a missing one counts as fine: nothing to protect yet). */
|
|
133
|
+
const looksLikeSqlite = (file) => {
|
|
134
|
+
if (!exists(file))
|
|
135
|
+
return true;
|
|
136
|
+
const fd = fs.openSync(file, 'r');
|
|
137
|
+
try {
|
|
138
|
+
const head = Buffer.alloc(16);
|
|
139
|
+
return fs.readSync(fd, head, 0, 16, 0) === 16 && head.toString('latin1') === SQLITE_HEADER;
|
|
140
|
+
}
|
|
141
|
+
finally {
|
|
142
|
+
fs.closeSync(fd);
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
const MAX_BACKUPS = 3;
|
|
146
|
+
const BACKUP_EVERY_MS = 6 * 3600 * 1000;
|
|
147
|
+
/** Moves the replaced copy into `dir` as a dated backup (at most one per 6 hours, the newest 3 kept); else deletes it. */
|
|
148
|
+
const keepBackup = (previous, dir) => {
|
|
149
|
+
if (!exists(previous))
|
|
150
|
+
return;
|
|
151
|
+
const backups = exists(dir) ? fs.readdirSync(dir).filter((n) => /^\d{13}$/.test(n)).sort() : [];
|
|
152
|
+
const newest = Number(backups[backups.length - 1] ?? 0);
|
|
153
|
+
if (Date.now() - newest < BACKUP_EVERY_MS) {
|
|
154
|
+
fs.rmSync(previous, { recursive: true, force: true });
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
fs.renameSync(previous, path.join(mkdirp(dir), String(Date.now())));
|
|
158
|
+
for (const old of [...backups, String(Date.now())].slice(0, -MAX_BACKUPS))
|
|
159
|
+
fs.rmSync(path.join(dir, old), { recursive: true, force: true });
|
|
160
|
+
};
|
|
112
161
|
export const saveClaudeMem = () => {
|
|
113
162
|
if (!claudeMemEnabled() || !exists(claudeMemPaths.local))
|
|
114
163
|
return;
|
|
@@ -116,12 +165,17 @@ export const saveClaudeMem = () => {
|
|
|
116
165
|
const fingerprint = databaseFingerprint(local);
|
|
117
166
|
if (fingerprint === lastSaved && exists(store))
|
|
118
167
|
return;
|
|
168
|
+
// A damaged copy (zero-filled after a crash, cut short) must never replace the store: that once destroyed the only copy.
|
|
169
|
+
if (!looksLikeSqlite(path.join(local, 'claude-mem.db'))) {
|
|
170
|
+
warn('claude-mem: the local database does not look valid, so it was not saved over the stored copy (' + local + ').');
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
119
173
|
const incoming = store + '.incoming';
|
|
120
174
|
const previous = store + '.previous';
|
|
121
175
|
fs.rmSync(incoming, { recursive: true, force: true });
|
|
122
176
|
// The database, its -wal and -shm files are copied together, so the copy is consistent with itself.
|
|
123
177
|
fs.cpSync(local, incoming, { recursive: true, filter: (src) => !/\.(pid|lock)$/i.test(src) });
|
|
124
|
-
// Swap without a window where no copy exists: old aside, new in, then
|
|
178
|
+
// Swap without a window where no copy exists: old aside, new in, then keep the old one as a dated backup.
|
|
125
179
|
fs.rmSync(previous, { recursive: true, force: true });
|
|
126
180
|
if (exists(store))
|
|
127
181
|
fs.renameSync(store, previous);
|
|
@@ -133,6 +187,6 @@ export const saveClaudeMem = () => {
|
|
|
133
187
|
fs.renameSync(previous, store);
|
|
134
188
|
throw e;
|
|
135
189
|
}
|
|
136
|
-
|
|
190
|
+
keepBackup(previous, store + '.backups');
|
|
137
191
|
lastSaved = fingerprint;
|
|
138
192
|
};
|
|
@@ -1,6 +1,16 @@
|
|
|
1
1
|
import type { ToolEnv } from '../toolchains/index.js';
|
|
2
|
-
|
|
2
|
+
/** Whose environment: the launch folder's at boot, or a project registered later (with the boot's base environment). */
|
|
3
|
+
export interface EnvTarget {
|
|
4
|
+
workspace: string;
|
|
5
|
+
project: string;
|
|
6
|
+
base: NodeJS.ProcessEnv;
|
|
7
|
+
}
|
|
8
|
+
export declare const agentEnv: (tools: Pick<ToolEnv, "vars" | "prepend" | "append">, target?: EnvTarget) => NodeJS.ProcessEnv;
|
|
3
9
|
/** Makes the agent environment machine-wide, so new terminal tabs and anything the agent starts see the same tools. */
|
|
4
10
|
export declare const persistEnvironment: (env: NodeJS.ProcessEnv, toolVars: string[]) => void;
|
|
5
|
-
/**
|
|
6
|
-
|
|
11
|
+
/**
|
|
12
|
+
* Adds variables and PATH folders machine-wide after boot (`sbx-db start`): new terminal tabs see them.
|
|
13
|
+
* additive: for a project registered later. Only variables not set yet, and folders go to the END of PATH, so what
|
|
14
|
+
* the boot project's terminals see never changes; the project's own sessions get its full environment anyway.
|
|
15
|
+
*/
|
|
16
|
+
export declare const addMachineEnvironment: (vars: Record<string, string>, dirs: string[], additive?: boolean) => void;
|
|
@@ -3,28 +3,28 @@ import path from 'node:path';
|
|
|
3
3
|
import { claudeDir, dataDir, dryRun, errMsg, isWin, testMode, mkdirp, powershell, session, stateDir, toolsDir, warn, workspace } from '../env.js';
|
|
4
4
|
/** Variables agent-sandbox itself sets (besides the toolchains' own). */
|
|
5
5
|
const AGENT_VARS = ['CLAUDE_CONFIG_DIR', 'CODEX_HOME', 'GEMINI_CLI_HOME', 'npm_config_cache', 'npm_config_update_notifier', 'AGENT_WORKSPACE', 'AGENT_DATA', 'AGENT_TOOLS', 'AGENT_PROJECT', 'AGENT_SANDBOX', 'AGENT_SANDBOX_WORKSPACE'];
|
|
6
|
-
export const agentEnv = (tools) => {
|
|
6
|
+
export const agentEnv = (tools, target = { workspace, project: session.project, base: process.env }) => {
|
|
7
7
|
const env = {
|
|
8
|
-
...
|
|
8
|
+
...target.base,
|
|
9
9
|
...tools.vars,
|
|
10
10
|
CLAUDE_CONFIG_DIR: claudeDir,
|
|
11
11
|
CODEX_HOME: path.join(stateDir, 'codex'),
|
|
12
12
|
GEMINI_CLI_HOME: path.join(stateDir, 'gemini'),
|
|
13
13
|
npm_config_cache: path.join(toolsDir, 'npm-cache'),
|
|
14
14
|
npm_config_update_notifier: 'false',
|
|
15
|
-
AGENT_WORKSPACE: workspace,
|
|
15
|
+
AGENT_WORKSPACE: target.workspace,
|
|
16
16
|
AGENT_DATA: dataDir,
|
|
17
17
|
AGENT_TOOLS: toolsDir,
|
|
18
|
-
AGENT_PROJECT:
|
|
18
|
+
AGENT_PROJECT: target.project,
|
|
19
19
|
// For project scripts: "am I in the sandbox, and where is the project?" (stable names; documented).
|
|
20
20
|
AGENT_SANDBOX: '1',
|
|
21
|
-
AGENT_SANDBOX_WORKSPACE: workspace,
|
|
21
|
+
AGENT_SANDBOX_WORKSPACE: target.workspace,
|
|
22
22
|
};
|
|
23
23
|
for (const dir of [env.CLAUDE_CONFIG_DIR, env.CODEX_HOME, env.GEMINI_CLI_HOME, env.npm_config_cache])
|
|
24
24
|
mkdirp(dir);
|
|
25
25
|
// The runner's own Node (bootstrap.ps1 puts it first on PATH) is not exposed: `node` is whatever nvm selected.
|
|
26
26
|
const runners = [path.join(toolsDir, 'node'), path.dirname(process.execPath)].map((d) => d.toLowerCase());
|
|
27
|
-
const base = (
|
|
27
|
+
const base = (target.base.PATH ?? '').split(path.delimiter).filter((d) => d && !runners.includes(d.toLowerCase()));
|
|
28
28
|
env.PATH = [...new Set([...tools.prepend, ...base, ...tools.append])].join(path.delimiter);
|
|
29
29
|
return env;
|
|
30
30
|
};
|
|
@@ -45,16 +45,20 @@ export const persistEnvironment = (env, toolVars) => {
|
|
|
45
45
|
warn('Could not persist the environment machine-wide: ' + errMsg(e));
|
|
46
46
|
}
|
|
47
47
|
};
|
|
48
|
-
/**
|
|
49
|
-
|
|
48
|
+
/**
|
|
49
|
+
* Adds variables and PATH folders machine-wide after boot (`sbx-db start`): new terminal tabs see them.
|
|
50
|
+
* additive: for a project registered later. Only variables not set yet, and folders go to the END of PATH, so what
|
|
51
|
+
* the boot project's terminals see never changes; the project's own sessions get its full environment anyway.
|
|
52
|
+
*/
|
|
53
|
+
export const addMachineEnvironment = (vars, dirs, additive = false) => {
|
|
50
54
|
if (!isWin || dryRun || testMode)
|
|
51
55
|
return;
|
|
52
56
|
const script = [
|
|
53
57
|
"$vars = '" + JSON.stringify(vars).replace(/'/g, "''") + "' | ConvertFrom-Json",
|
|
54
|
-
"foreach ($p in $vars.PSObject.Properties) { [Environment]::SetEnvironmentVariable($p.Name, [string]$p.Value, 'Machine') }",
|
|
58
|
+
"foreach ($p in $vars.PSObject.Properties) { " + (additive ? "if ([Environment]::GetEnvironmentVariable($p.Name, 'Machine')) { continue }; " : '') + "[Environment]::SetEnvironmentVariable($p.Name, [string]$p.Value, 'Machine') }",
|
|
55
59
|
"$path = [Environment]::GetEnvironmentVariable('Path', 'Machine') -split ';'",
|
|
56
60
|
"$add = '" + JSON.stringify(dirs).replace(/'/g, "''") + "' | ConvertFrom-Json | Where-Object { $path -notcontains $_ }",
|
|
57
|
-
"if ($add) { [Environment]::SetEnvironmentVariable('Path', ((@($add) + $path) -join ';'), 'Machine') }",
|
|
61
|
+
"if ($add) { [Environment]::SetEnvironmentVariable('Path', (" + (additive ? '($path + @($add))' : '(@($add) + $path)') + " -join ';'), 'Machine') }",
|
|
58
62
|
].join('\n');
|
|
59
63
|
try {
|
|
60
64
|
powershell(script);
|
|
@@ -1 +1,9 @@
|
|
|
1
|
-
|
|
1
|
+
/** Hooks of the launch folder (C:\AgentLaunch\hooks), or of a project registered later (...\projects\<name>\hooks). */
|
|
2
|
+
export interface HookTarget {
|
|
3
|
+
root: string;
|
|
4
|
+
cwd: string;
|
|
5
|
+
}
|
|
6
|
+
export declare const projectHooks: (name: string, cwd: string) => HookTarget;
|
|
7
|
+
export declare const runHooks: (stage: string, env: NodeJS.ProcessEnv, target?: HookTarget) => void;
|
|
8
|
+
/** The same without blocking: the session daemon keeps answering other requests while a project's hooks run. */
|
|
9
|
+
export declare const runHooksAsync: (stage: string, env: NodeJS.ProcessEnv, target: HookTarget) => Promise<void>;
|
|
@@ -3,6 +3,7 @@ import fs from 'node:fs';
|
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
import { spawnSync } from 'node:child_process';
|
|
5
5
|
import { SYSTEM } from '../../shared/system.js';
|
|
6
|
+
import { spawnAsync } from '../../shared/download.js';
|
|
6
7
|
import { exists, isWin, launchDir, log, session, warn, workspace } from '../env.js';
|
|
7
8
|
const commandFor = (file) => {
|
|
8
9
|
const ext = path.extname(file).toLowerCase();
|
|
@@ -16,21 +17,34 @@ const commandFor = (file) => {
|
|
|
16
17
|
return [SYSTEM.cmd(), ['/d', '/c', file]];
|
|
17
18
|
return null;
|
|
18
19
|
};
|
|
19
|
-
|
|
20
|
-
|
|
20
|
+
const BOOT = { root: path.join(launchDir, 'hooks'), cwd: workspace };
|
|
21
|
+
export const projectHooks = (name, cwd) => ({ root: path.join(launchDir, 'projects', name, 'hooks'), cwd });
|
|
22
|
+
const hooksOf = (stage, target) => {
|
|
23
|
+
const dir = path.join(target.root, stage);
|
|
21
24
|
if (!exists(dir))
|
|
22
|
-
return;
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
return [];
|
|
26
|
+
return fs.readdirSync(dir).sort().flatMap((name) => { const command = commandFor(path.join(dir, name)); return command ? [{ name, command }] : []; });
|
|
27
|
+
};
|
|
28
|
+
const failed = (stage, name, status) => {
|
|
29
|
+
const message = 'Hook failed (' + stage + '/' + name + ', exit ' + status + ')';
|
|
30
|
+
if (session.hooks.failFast)
|
|
31
|
+
throw new Error(message);
|
|
32
|
+
warn(message);
|
|
33
|
+
};
|
|
34
|
+
export const runHooks = (stage, env, target = BOOT) => {
|
|
35
|
+
for (const { name, command } of hooksOf(stage, target)) {
|
|
36
|
+
log('Hook [' + stage + ']: ' + name);
|
|
37
|
+
const result = spawnSync(command[0], command[1], { stdio: 'inherit', cwd: target.cwd, env });
|
|
38
|
+
if (result.status !== 0)
|
|
39
|
+
failed(stage, name, result.status);
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
/** The same without blocking: the session daemon keeps answering other requests while a project's hooks run. */
|
|
43
|
+
export const runHooksAsync = async (stage, env, target) => {
|
|
44
|
+
for (const { name, command } of hooksOf(stage, target)) {
|
|
27
45
|
log('Hook [' + stage + ']: ' + name);
|
|
28
|
-
const
|
|
29
|
-
if (
|
|
30
|
-
|
|
31
|
-
const message = 'Hook failed (' + stage + '/' + name + ', exit ' + result.status + ')';
|
|
32
|
-
if (session.hooks.failFast)
|
|
33
|
-
throw new Error(message);
|
|
34
|
-
warn(message);
|
|
46
|
+
const status = await spawnAsync(command[0], command[1], { stdio: 'ignore', cwd: target.cwd, env, windowsHide: true });
|
|
47
|
+
if (status !== 0)
|
|
48
|
+
failed(stage, name, status);
|
|
35
49
|
}
|
|
36
50
|
};
|
|
@@ -6,5 +6,14 @@ export type LanState = 'blocked' | 'open' | 'offline';
|
|
|
6
6
|
* all, the block stays in place: being offline is never a reason to open the LAN.
|
|
7
7
|
*/
|
|
8
8
|
export declare const applyNetworkPolicy: (ptyHostExe: string | null) => Promise<LanState>;
|
|
9
|
+
/** HTTP_PROXY & co. for everything in the sandbox: its own proxy (allowOnly) or yours (network.proxy). */
|
|
10
|
+
export declare const proxyEnv: () => Record<string, string>;
|
|
11
|
+
/**
|
|
12
|
+
* network.allowOnly, after the tools are installed: the sandbox's proxy (a copy of Node named sbx-netproxy.exe, so the
|
|
13
|
+
* firewall can tell it apart) is the only program allowed out, besides DNS and DHCP; Windows and browsers use it as
|
|
14
|
+
* the system proxy, everything else through HTTP_PROXY. A guardrail for agents that behave: an admin in the sandbox
|
|
15
|
+
* could undo it, which is why sandbox.networking false is the only hard isolation.
|
|
16
|
+
*/
|
|
17
|
+
export declare const applyAllowOnly: () => Promise<boolean>;
|
|
9
18
|
/** Guest IPv4 addresses the host can use to reach session ports. */
|
|
10
19
|
export declare const guestAddresses: () => string[];
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
// Guest firewall: block the host's LAN (keeping DNS/DHCP to the gateway) and let the host reach session ports.
|
|
2
2
|
import dns from 'node:dns';
|
|
3
|
+
import fs from 'node:fs';
|
|
3
4
|
import os from 'node:os';
|
|
4
|
-
import
|
|
5
|
-
import {
|
|
5
|
+
import path from 'node:path';
|
|
6
|
+
import { spawn, spawnSync } from 'node:child_process';
|
|
7
|
+
import { expandAllowList, PROXY_PORT, relayPort, withBlockedHosts } from '../../shared/netpolicy.js';
|
|
8
|
+
import { buildFirewallCommands, ipv4DnsServers, isIPv4, parseDefaultGateways, parseDnsServers } from '../../shared/netrules.js';
|
|
6
9
|
import { SYSTEM } from '../../shared/system.js';
|
|
7
|
-
import { dryRun, isWin, log, session, warn } from '../env.js';
|
|
10
|
+
import { dryRun, errMsg, isWin, launchDir, log, session, toolsDir, warn } from '../env.js';
|
|
8
11
|
const ATTACH_RULE = 'AgentSandbox-Attach';
|
|
9
12
|
const netsh = (args) => {
|
|
10
13
|
const r = spawnSync(SYSTEM.netsh(), args, { encoding: 'utf8', windowsHide: true });
|
|
@@ -68,7 +71,21 @@ export const applyNetworkPolicy = async (ptyHostExe) => {
|
|
|
68
71
|
const block = session.network.blockPrivateRanges;
|
|
69
72
|
const exempt = block ? discoverExemptIps() : [];
|
|
70
73
|
const lanRules = block ? buildFirewallCommands(exempt) : [];
|
|
71
|
-
const commands = [...lanRules, ...(ptyHostExe && session.attach.enabled ? attachRule(ptyHostExe) : [])];
|
|
74
|
+
const commands = [...lanRules, ...(ptyHostExe && session.attach.enabled ? attachRule(ptyHostExe) : []), ...forwardRule()];
|
|
75
|
+
if (isWin && !dryRun) {
|
|
76
|
+
try {
|
|
77
|
+
applyBlockedHosts();
|
|
78
|
+
}
|
|
79
|
+
catch (e) {
|
|
80
|
+
warn('network.blockHosts could not be applied: ' + errMsg(e));
|
|
81
|
+
}
|
|
82
|
+
try {
|
|
83
|
+
applyDns();
|
|
84
|
+
}
|
|
85
|
+
catch (e) {
|
|
86
|
+
warn('network.dns could not be applied: ' + errMsg(e));
|
|
87
|
+
}
|
|
88
|
+
}
|
|
72
89
|
if (!block)
|
|
73
90
|
log('Private-range blocking disabled by config.');
|
|
74
91
|
if (block)
|
|
@@ -95,5 +112,81 @@ export const applyNetworkPolicy = async (ptyHostExe) => {
|
|
|
95
112
|
log('LAN blocked in the guest firewall (10/8, 172.16/12, 192.168/16, 100.64/10, link-local, multicast, IPv6 local, SMB); DNS/DHCP to the gateway allowed.');
|
|
96
113
|
return 'blocked';
|
|
97
114
|
};
|
|
115
|
+
// ---- the rest of the network settings -----------------------------------------------------------------------------
|
|
116
|
+
const FORWARD_RULE = 'AgentSandbox-Forward';
|
|
117
|
+
const ALLOW_RULES = ['AgentSandbox-Proxy-Out', 'AgentSandbox-DNS-Out-UDP', 'AgentSandbox-DNS-Out-TCP', 'AgentSandbox-DHCP-Out'];
|
|
118
|
+
const HOSTS_FILE = path.join(process.env.WINDIR ?? 'C:\\Windows', 'System32', 'drivers', 'etc', 'hosts');
|
|
119
|
+
/** network.blockHosts: those names go nowhere (the sandbox's hosts file; the registry and files are new every boot). */
|
|
120
|
+
const applyBlockedHosts = () => {
|
|
121
|
+
const hosts = session.network.blockHosts ?? [];
|
|
122
|
+
if (!hosts.length)
|
|
123
|
+
return;
|
|
124
|
+
const text = fs.existsSync(HOSTS_FILE) ? fs.readFileSync(HOSTS_FILE, 'utf8') : '';
|
|
125
|
+
fs.writeFileSync(HOSTS_FILE, withBlockedHosts(text, hosts));
|
|
126
|
+
log('Blocked hosts (network.blockHosts): ' + hosts.join(', '));
|
|
127
|
+
};
|
|
128
|
+
/** network.dns: these servers on every connected adapter. */
|
|
129
|
+
const applyDns = () => {
|
|
130
|
+
const servers = (session.network.dns ?? []).filter(isIPv4);
|
|
131
|
+
if (!servers.length)
|
|
132
|
+
return;
|
|
133
|
+
const r = spawnSync(SYSTEM.powershell(), ['-NoLogo', '-NoProfile', '-Command', "Get-NetAdapter | Where-Object Status -eq 'Up' | Set-DnsClientServerAddress -ServerAddresses " + servers.map((s) => "'" + s + "'").join(',')], { encoding: 'utf8', windowsHide: true });
|
|
134
|
+
if (r.status !== 0)
|
|
135
|
+
throw new Error('could not set the DNS servers: ' + (r.stderr ?? '').trim().slice(0, 300));
|
|
136
|
+
log('DNS servers (network.dns): ' + servers.join(', '));
|
|
137
|
+
};
|
|
138
|
+
/** network.forwardPorts: the relays (in the daemon) take connections from the PC only, i.e. the sandbox's own subnet. */
|
|
139
|
+
const forwardRule = () => {
|
|
140
|
+
const forwards = session.network.forwardPorts ?? [];
|
|
141
|
+
return forwards.length ? [
|
|
142
|
+
['advfirewall', 'firewall', 'delete', 'rule', 'name=' + FORWARD_RULE],
|
|
143
|
+
['advfirewall', 'firewall', 'add', 'rule', 'name=' + FORWARD_RULE, 'dir=in', 'action=allow', 'enable=yes', 'profile=any', 'protocol=tcp', 'remoteip=LocalSubnet', 'localport=' + forwards.map((_f, i) => relayPort(i)).join(',')],
|
|
144
|
+
] : [];
|
|
145
|
+
};
|
|
146
|
+
/** HTTP_PROXY & co. for everything in the sandbox: its own proxy (allowOnly) or yours (network.proxy). */
|
|
147
|
+
export const proxyEnv = () => {
|
|
148
|
+
const own = (session.network.allowOnly ?? []).length > 0;
|
|
149
|
+
const url = own ? 'http://127.0.0.1:' + PROXY_PORT : session.network.proxy ?? '';
|
|
150
|
+
if (!url)
|
|
151
|
+
return {};
|
|
152
|
+
const noProxy = 'localhost,127.0.0.1,::1';
|
|
153
|
+
return { HTTP_PROXY: url, HTTPS_PROXY: url, http_proxy: url, https_proxy: url, NO_PROXY: noProxy, no_proxy: noProxy };
|
|
154
|
+
};
|
|
155
|
+
/**
|
|
156
|
+
* network.allowOnly, after the tools are installed: the sandbox's proxy (a copy of Node named sbx-netproxy.exe, so the
|
|
157
|
+
* firewall can tell it apart) is the only program allowed out, besides DNS and DHCP; Windows and browsers use it as
|
|
158
|
+
* the system proxy, everything else through HTTP_PROXY. A guardrail for agents that behave: an admin in the sandbox
|
|
159
|
+
* could undo it, which is why sandbox.networking false is the only hard isolation.
|
|
160
|
+
*/
|
|
161
|
+
export const applyAllowOnly = async () => {
|
|
162
|
+
const hosts = session.network.allowOnly ?? [];
|
|
163
|
+
if (!session.networking || !hosts.length)
|
|
164
|
+
return false;
|
|
165
|
+
if (!isWin || dryRun) {
|
|
166
|
+
log('(dry run) would allow only: ' + hosts.join(', '));
|
|
167
|
+
return false;
|
|
168
|
+
}
|
|
169
|
+
const exe = path.join(toolsDir, 'netproxy', 'sbx-netproxy.exe');
|
|
170
|
+
fs.mkdirSync(path.dirname(exe), { recursive: true });
|
|
171
|
+
if (!fs.existsSync(exe) || fs.statSync(exe).size !== fs.statSync(process.execPath).size)
|
|
172
|
+
fs.copyFileSync(process.execPath, exe);
|
|
173
|
+
spawn(exe, [path.join(launchDir, 'runtime', 'netproxy.js')], { detached: true, stdio: 'ignore', windowsHide: true }).unref();
|
|
174
|
+
const add = (name, extra) => ['advfirewall', 'firewall', 'add', 'rule', 'name=' + name, 'dir=out', 'action=allow', 'enable=yes', 'profile=any', ...extra];
|
|
175
|
+
run([
|
|
176
|
+
...ALLOW_RULES.map((n) => ['advfirewall', 'firewall', 'delete', 'rule', 'name=' + n]),
|
|
177
|
+
add('AgentSandbox-Proxy-Out', ['program=' + exe]),
|
|
178
|
+
add('AgentSandbox-DNS-Out-UDP', ['protocol=udp', 'remoteport=53']),
|
|
179
|
+
add('AgentSandbox-DNS-Out-TCP', ['protocol=tcp', 'remoteport=53']),
|
|
180
|
+
add('AgentSandbox-DHCP-Out', ['protocol=udp', 'remoteport=67', 'localport=68']),
|
|
181
|
+
['advfirewall', 'set', 'allprofiles', 'firewallpolicy', 'blockinbound,blockoutbound'],
|
|
182
|
+
['winhttp', 'set', 'proxy', '127.0.0.1:' + PROXY_PORT, '<local>'],
|
|
183
|
+
]);
|
|
184
|
+
const internet = 'HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings';
|
|
185
|
+
for (const [name, type, value] of [['ProxyEnable', 'REG_DWORD', '1'], ['ProxyServer', 'REG_SZ', '127.0.0.1:' + PROXY_PORT], ['ProxyOverride', 'REG_SZ', '<local>']]) {
|
|
186
|
+
spawnSync(SYSTEM.reg(), ['add', internet, '/v', name, '/t', type, '/d', value, '/f'], { windowsHide: true, stdio: 'ignore' });
|
|
187
|
+
}
|
|
188
|
+
log('Only these hosts can be reached now (network.allowOnly): ' + expandAllowList(hosts).join(', ') + '. Refused ones are listed in logs\\netproxy.log.');
|
|
189
|
+
return true;
|
|
190
|
+
};
|
|
98
191
|
/** Guest IPv4 addresses the host can use to reach session ports. */
|
|
99
192
|
export const guestAddresses = () => Object.values(os.networkInterfaces()).flat().filter((i) => Boolean(i) && i.family === 'IPv4' && !i.internal).map((i) => i.address);
|
package/dist/guest/setup/user.js
CHANGED
|
@@ -44,4 +44,8 @@ export const setupGitConfig = (env) => {
|
|
|
44
44
|
spawnSync(git, ['config', '--global', '--add', 'safe.directory', '*'], { env: rest, windowsHide: true, stdio: 'ignore' });
|
|
45
45
|
// Windows long paths are on in the sandbox, but git skips files over 260 characters unless told.
|
|
46
46
|
spawnSync(git, ['config', '--global', 'core.longpaths', 'true'], { env: rest, windowsHide: true, stdio: 'ignore' });
|
|
47
|
+
// Git for Windows' system config says autocrlf=true: checkouts made in the sandbox (worktrees, clones) got CRLF and
|
|
48
|
+
// tools that want LF (rustfmt, shellcheck, prettier) failed on every file. "input" keeps the line endings the repo
|
|
49
|
+
// has, and a checkout from your PC (CRLF in the folder) still shows as unchanged.
|
|
50
|
+
spawnSync(git, ['config', '--global', 'core.autocrlf', 'input'], { env: rest, windowsHide: true, stdio: 'ignore' });
|
|
47
51
|
};
|
|
@@ -17,6 +17,8 @@ export interface CliTool {
|
|
|
17
17
|
subdir?: string;
|
|
18
18
|
/** What the tool is for (summary and docs). */
|
|
19
19
|
about: string;
|
|
20
|
+
/** Rough download size for the progress line. */
|
|
21
|
+
size: string;
|
|
20
22
|
}
|
|
21
23
|
export declare const CLI_TOOLS: readonly [{
|
|
22
24
|
readonly name: "gh";
|
|
@@ -24,12 +26,14 @@ export declare const CLI_TOOLS: readonly [{
|
|
|
24
26
|
readonly asset: (arch: Arch) => RegExp;
|
|
25
27
|
readonly exe: "gh.exe";
|
|
26
28
|
readonly about: "GitHub CLI";
|
|
29
|
+
readonly size: "15 MB";
|
|
27
30
|
}, {
|
|
28
31
|
readonly name: "zstd";
|
|
29
32
|
readonly repo: "facebook/zstd";
|
|
30
33
|
readonly asset: () => RegExp;
|
|
31
34
|
readonly exe: "zstd.exe";
|
|
32
35
|
readonly about: "Zstandard compression";
|
|
36
|
+
readonly size: "2 MB";
|
|
33
37
|
}];
|
|
34
38
|
export type CliName = (typeof CLI_TOOLS)[number]['name'] | 'openssl';
|
|
35
39
|
export declare const CLI_NAMES: readonly CliName[];
|
|
@@ -4,9 +4,9 @@ export const pwshAsset = (arch) => (arch === 'arm64' ? /^PowerShell-\d+\.\d+\.\d
|
|
|
4
4
|
export const binstallAsset = (arch) => (arch === 'arm64' ? /^cargo-binstall-aarch64-pc-windows-msvc\.zip$/ : /^cargo-binstall-x86_64-pc-windows-msvc\.zip$/);
|
|
5
5
|
export const CLI_TOOLS = [
|
|
6
6
|
// gh_2.102.0_windows_amd64.zip holds bin\gh.exe.
|
|
7
|
-
{ name: 'gh', repo: 'cli/cli', asset: (arch) => (arch === 'arm64' ? /^gh_\d+\.\d+\.\d+_windows_arm64\.zip$/ : /^gh_\d+\.\d+\.\d+_windows_amd64\.zip$/), exe: 'gh.exe', about: 'GitHub CLI' },
|
|
7
|
+
{ name: 'gh', repo: 'cli/cli', asset: (arch) => (arch === 'arm64' ? /^gh_\d+\.\d+\.\d+_windows_arm64\.zip$/ : /^gh_\d+\.\d+\.\d+_windows_amd64\.zip$/), exe: 'gh.exe', about: 'GitHub CLI', size: '15 MB' },
|
|
8
8
|
// zstd-v1.5.7-win64.zip; there is no arm64 build, and Windows on Arm runs the x64 one.
|
|
9
|
-
{ name: 'zstd', repo: 'facebook/zstd', asset: () => /^zstd-v\d+\.\d+\.\d+-win64\.zip$/, exe: 'zstd.exe', about: 'Zstandard compression' },
|
|
9
|
+
{ name: 'zstd', repo: 'facebook/zstd', asset: () => /^zstd-v\d+\.\d+\.\d+-win64\.zip$/, exe: 'zstd.exe', about: 'Zstandard compression', size: '2 MB' },
|
|
10
10
|
];
|
|
11
11
|
export const CLI_NAMES = [...CLI_TOOLS.map((t) => t.name), 'openssl'];
|
|
12
12
|
/**
|
|
@@ -2,39 +2,40 @@
|
|
|
2
2
|
// `openssl` shim onto the copy Git for Windows already ships.
|
|
3
3
|
import fs from 'node:fs';
|
|
4
4
|
import path from 'node:path';
|
|
5
|
-
import { dryRun, errMsg, exists, log, mkdirp, stateDir, warn
|
|
5
|
+
import { dryRun, errMsg, exists, log, mkdirp, stateDir, warn } from '../env.js';
|
|
6
|
+
import { projectWorkspace } from '../project-context.js';
|
|
6
7
|
import { CLI_TOOLS, decideCli } from './catalogue.js';
|
|
7
8
|
import { arch, tool } from './common.js';
|
|
8
9
|
import { setupSingleExe } from './runtimes.js';
|
|
10
|
+
import { ensureCompiled } from '../helpers.js';
|
|
9
11
|
/** gh keeps `gh auth login` here, under the agent state (persists like Claude's own login; never copied from the PC). */
|
|
10
12
|
export const ghConfigDir = () => path.join(stateDir, 'gh');
|
|
11
13
|
const toolVars = {
|
|
12
14
|
gh: () => ({ GH_CONFIG_DIR: mkdirp(ghConfigDir()), GH_NO_UPDATE_NOTIFIER: '1', GH_NO_EXTENSION_UPDATE_NOTIFIER: '1' }),
|
|
13
15
|
};
|
|
14
16
|
/**
|
|
15
|
-
* openssl.
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
* by programs that use cmd /c; Rust's Command::new("openssl") looks only for openssl.exe.)
|
|
17
|
+
* tools\shims\openssl.exe (sandbox/openssl.cs), a launcher for Git's mingw64\bin\openssl.exe. A real .exe so programs
|
|
18
|
+
* that call CreateProcess directly (Rust's Command::new("openssl")) find it, and only the shim is on PATH: mingw64\bin
|
|
19
|
+
* itself would bring Git's runtime DLLs along and could shadow MinGW's gcc from the C/C++ step.
|
|
19
20
|
*/
|
|
20
21
|
const shimOpenssl = (env) => {
|
|
21
|
-
|
|
22
|
-
if (!exists(exe)) {
|
|
22
|
+
if (!exists(tool('git', 'mingw64', 'bin', 'openssl.exe'))) {
|
|
23
23
|
env.summary.push('openssl: not in this Git for Windows (skipped)');
|
|
24
24
|
return;
|
|
25
25
|
}
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
env.
|
|
26
|
+
const shims = mkdirp(tool('shims'));
|
|
27
|
+
fs.copyFileSync(ensureCompiled('openssl'), path.join(shims, 'openssl.exe'));
|
|
28
|
+
// An earlier version wrote a .cmd; it would still win for shells that prefer it.
|
|
29
|
+
fs.rmSync(path.join(shims, 'openssl.cmd'), { force: true });
|
|
30
|
+
env.prepend.push(shims);
|
|
31
|
+
env.summary.push('openssl: Git for Windows\' copy');
|
|
31
32
|
};
|
|
32
33
|
/**
|
|
33
34
|
* Installs the tools toolchains.cli asks for. Settings still "auto" here (normally the host decides) use the same
|
|
34
35
|
* rules on the workspace as the host would. The gh rule is enforced here again, whatever the host sent.
|
|
35
36
|
*/
|
|
36
37
|
export const setupCli = async (env, settings, gitAccess, refresh = false) => {
|
|
37
|
-
const decisions = decideCli(settings, { gitAccess, hasGithubDir: exists(path.join(
|
|
38
|
+
const decisions = decideCli(settings, { gitAccess, hasGithubDir: exists(path.join(projectWorkspace(), '.github')) });
|
|
38
39
|
if (settings.gh && !decisions.gh.on) {
|
|
39
40
|
env.summary.push('gh: off (' + decisions.gh.reason + ')');
|
|
40
41
|
// A login from an earlier full-access sandbox is still on disk; the agent could read the token from there.
|
|
@@ -50,15 +51,22 @@ export const setupCli = async (env, settings, gitAccess, refresh = false) => {
|
|
|
50
51
|
if (!decisions[name].on)
|
|
51
52
|
continue;
|
|
52
53
|
try {
|
|
53
|
-
await setupSingleExe(env, name, entry.repo, entry.asset(arch), entry.exe, tool('cli', name), { refresh, subdir: entry.subdir });
|
|
54
|
+
await setupSingleExe(env, name, entry.repo, entry.asset(arch), entry.exe, tool('cli', name), { refresh, subdir: entry.subdir, size: entry.size });
|
|
54
55
|
Object.assign(env.vars, toolVars[name]?.() ?? {});
|
|
55
56
|
}
|
|
56
57
|
catch (e) {
|
|
57
58
|
// One tool failing never takes the others down.
|
|
58
|
-
warn(name + '
|
|
59
|
+
warn(name + ' could not be set up and is skipped; the other tools are not affected. Reason: ' + errMsg(e));
|
|
59
60
|
env.summary.push(entry.name + ': FAILED');
|
|
60
61
|
}
|
|
61
62
|
}
|
|
62
|
-
if (decisions.openssl.on)
|
|
63
|
-
|
|
63
|
+
if (decisions.openssl.on) {
|
|
64
|
+
try {
|
|
65
|
+
shimOpenssl(env);
|
|
66
|
+
}
|
|
67
|
+
catch (e) {
|
|
68
|
+
warn('openssl could not be set up and is skipped (Git Bash still has its own). Reason: ' + errMsg(e));
|
|
69
|
+
env.summary.push('openssl: FAILED');
|
|
70
|
+
}
|
|
71
|
+
}
|
|
64
72
|
};
|