windows-development-sandbox 1.5.0 → 1.7.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/README.md +1 -0
- package/config.example.json +17 -1
- package/dist/cli/args.d.ts +13 -2
- package/dist/cli/args.js +95 -24
- package/dist/cli/commands/accounts.js +45 -17
- package/dist/cli/commands/context.d.ts +2 -0
- package/dist/cli/commands/context.js +9 -2
- package/dist/cli/commands/data/clean.js +32 -9
- package/dist/cli/commands/index.d.ts +1 -0
- package/dist/cli/commands/index.js +1 -0
- package/dist/cli/commands/launch/add-root.d.ts +3 -2
- package/dist/cli/commands/launch/add-root.js +11 -10
- package/dist/cli/commands/launch/launch.js +57 -4
- package/dist/cli/commands/launch/prepare.js +3 -1
- package/dist/cli/commands/maintenance/audit.js +1 -1
- package/dist/cli/commands/maintenance/clean.d.ts +1 -1
- package/dist/cli/commands/maintenance/clean.js +17 -3
- package/dist/cli/commands/maintenance/config.d.ts +1 -1
- package/dist/cli/commands/maintenance/config.js +112 -10
- package/dist/cli/commands/maintenance/doctor.d.ts +1 -1
- package/dist/cli/commands/maintenance/doctor.js +2 -4
- package/dist/cli/commands/maintenance/migrate.d.ts +2 -1
- package/dist/cli/commands/maintenance/migrate.js +19 -4
- package/dist/cli/commands/maintenance/sync.js +2 -0
- package/dist/cli/commands/maintenance/update.d.ts +2 -0
- package/dist/cli/commands/maintenance/update.js +27 -4
- package/dist/cli/commands/projects/here.js +12 -7
- package/dist/cli/commands/projects/projects.js +26 -17
- package/dist/cli/commands/registry.js +7 -0
- package/dist/cli/commands/repair/checks/agents.d.ts +2 -0
- package/dist/cli/commands/repair/checks/agents.js +70 -0
- package/dist/cli/commands/repair/checks/common.d.ts +8 -0
- package/dist/cli/commands/repair/checks/common.js +22 -0
- package/dist/cli/commands/repair/checks/data.d.ts +2 -0
- package/dist/cli/commands/repair/checks/data.js +241 -0
- package/dist/cli/commands/repair/checks/index.d.ts +2 -0
- package/dist/cli/commands/repair/checks/index.js +20 -0
- package/dist/cli/commands/repair/checks/install.d.ts +5 -0
- package/dist/cli/commands/repair/checks/install.js +318 -0
- package/dist/cli/commands/repair/checks/machine.d.ts +2 -0
- package/dist/cli/commands/repair/checks/machine.js +232 -0
- package/dist/cli/commands/repair/checks/network.d.ts +6 -0
- package/dist/cli/commands/repair/checks/network.js +60 -0
- package/dist/cli/commands/repair/checks/pc.d.ts +4 -0
- package/dist/cli/commands/repair/checks/pc.js +55 -0
- package/dist/cli/commands/repair/checks/sandbox.d.ts +2 -0
- package/dist/cli/commands/repair/checks/sandbox.js +267 -0
- package/dist/cli/commands/repair/checks/settings.d.ts +2 -0
- package/dist/cli/commands/repair/checks/settings.js +169 -0
- package/dist/cli/commands/repair/checks/vpn.d.ts +2 -0
- package/dist/cli/commands/repair/checks/vpn.js +53 -0
- package/dist/cli/commands/repair/engine.d.ts +32 -0
- package/dist/cli/commands/repair/engine.js +127 -0
- package/dist/cli/commands/repair/env.d.ts +7 -0
- package/dist/cli/commands/repair/env.js +49 -0
- package/dist/cli/commands/repair/index.d.ts +1 -9
- package/dist/cli/commands/repair/index.js +2 -54
- package/dist/cli/commands/repair/log.d.ts +17 -0
- package/dist/cli/commands/repair/log.js +82 -0
- package/dist/cli/commands/repair/printer.d.ts +32 -0
- package/dist/cli/commands/repair/printer.js +132 -0
- package/dist/cli/commands/repair/run.d.ts +33 -0
- package/dist/cli/commands/repair/run.js +133 -0
- package/dist/cli/commands/repair/types.d.ts +97 -9
- package/dist/cli/commands/repair/types.js +11 -7
- package/dist/cli/commands/resume.js +2 -2
- package/dist/cli/commands/sessions/list.js +5 -2
- package/dist/cli/commands/sessions/status.d.ts +2 -0
- package/dist/cli/commands/sessions/status.js +27 -6
- package/dist/cli/commands/setup/index.d.ts +5 -0
- package/dist/cli/commands/setup/index.js +25 -1
- package/dist/cli/commands/storage/index.d.ts +2 -0
- package/dist/cli/commands/storage/index.js +2 -0
- package/dist/cli/commands/storage/offer.d.ts +3 -0
- package/dist/cli/commands/storage/offer.js +85 -0
- package/dist/cli/commands/storage/storage.d.ts +8 -0
- package/dist/cli/commands/storage/storage.js +171 -0
- package/dist/cli/commands/user-config.js +1 -1
- package/dist/cli/commands/vpn.d.ts +4 -0
- package/dist/cli/commands/vpn.js +75 -0
- package/dist/cli/commands/web.d.ts +4 -0
- package/dist/cli/commands/web.js +95 -0
- package/dist/cli/history.js +1 -1
- package/dist/cli/index.js +46 -3
- package/dist/cli/manifest.d.ts +303 -29
- package/dist/cli/manifest.js +173 -43
- package/dist/cli/menu/add-agent.d.ts +47 -0
- package/dist/cli/menu/add-agent.js +168 -0
- package/dist/cli/menu/apps.d.ts +31 -2
- package/dist/cli/menu/apps.js +44 -5
- package/dist/cli/menu/command-fields.d.ts +18 -0
- package/dist/cli/menu/command-fields.js +61 -0
- package/dist/cli/menu/command-form.d.ts +22 -0
- package/dist/cli/menu/command-form.js +169 -46
- package/dist/cli/menu/data-folder.d.ts +18 -0
- package/dist/cli/menu/data-folder.js +99 -0
- package/dist/cli/menu/menu.d.ts +1 -1
- package/dist/cli/menu/menu.js +11 -8
- package/dist/cli/menu/pages/accounts-page.js +55 -24
- package/dist/cli/menu/pages/agents-page.d.ts +66 -0
- package/dist/cli/menu/pages/agents-page.js +338 -0
- package/dist/cli/menu/pages/apps-page.js +1 -2
- package/dist/cli/menu/pages/list-page.d.ts +16 -3
- package/dist/cli/menu/pages/list-page.js +40 -8
- package/dist/cli/menu/pages/maintenance-page.d.ts +9 -0
- package/dist/cli/menu/pages/maintenance-page.js +161 -72
- package/dist/cli/menu/pages/sandbox-page.d.ts +3 -0
- package/dist/cli/menu/pages/sandbox-page.js +132 -43
- package/dist/cli/menu/pages/sessions-page.d.ts +4 -0
- package/dist/cli/menu/pages/sessions-page.js +41 -25
- package/dist/cli/menu/pages/settings-page.d.ts +8 -4
- package/dist/cli/menu/pages/settings-page.js +36 -13
- package/dist/cli/menu/settings/categories.d.ts +2 -0
- package/dist/cli/menu/settings/categories.js +19 -44
- package/dist/cli/menu/settings/collections/collection-editor.d.ts +7 -1
- package/dist/cli/menu/settings/collections/collection-editor.js +12 -8
- package/dist/cli/menu/settings/collections/map-editor.js +5 -1
- package/dist/cli/menu/settings/collections/object-list-editor.js +2 -2
- package/dist/cli/menu/settings/collections/object-map-editor.js +2 -2
- package/dist/cli/menu/settings/collections/string-list-editor.d.ts +11 -1
- package/dist/cli/menu/settings/collections/string-list-editor.js +23 -0
- package/dist/cli/menu/settings/index.d.ts +1 -1
- package/dist/cli/menu/settings/index.js +1 -1
- package/dist/cli/menu/settings/object-editor.d.ts +5 -1
- package/dist/cli/menu/settings/object-editor.js +15 -4
- package/dist/cli/menu/settings/path-kind.d.ts +20 -0
- package/dist/cli/menu/settings/path-kind.js +44 -0
- package/dist/cli/menu/settings/schema-node.d.ts +9 -0
- package/dist/cli/menu/settings/schema-node.js +26 -0
- package/dist/cli/menu/settings/value-editor.d.ts +5 -0
- package/dist/cli/menu/settings/value-editor.js +51 -18
- package/dist/cli/menu/several.js +7 -5
- package/dist/cli/menu/shell.d.ts +37 -10
- package/dist/cli/menu/shell.js +90 -10
- package/dist/cli/menu/vpn-login.d.ts +16 -0
- package/dist/cli/menu/vpn-login.js +66 -0
- package/dist/cli/output/print.d.ts +2 -0
- package/dist/cli/output/print.js +8 -1
- package/dist/cli/services/accounts-service.d.ts +2 -0
- package/dist/cli/services/accounts-service.js +2 -2
- package/dist/cli/services/health-service.d.ts +0 -6
- package/dist/cli/services/health-service.js +5 -42
- package/dist/cli/services/index.d.ts +3 -1
- package/dist/cli/services/index.js +3 -1
- package/dist/cli/services/migrate-service.js +1 -1
- package/dist/cli/services/update-service.d.ts +2 -0
- package/dist/cli/services/update-service.js +13 -6
- package/dist/cli/services/vpn-service.d.ts +28 -0
- package/dist/cli/services/vpn-service.js +46 -0
- package/dist/cli/services/web-service.d.ts +22 -0
- package/dist/cli/services/web-service.js +111 -0
- package/dist/cli/tui/app.d.ts +6 -3
- package/dist/cli/tui/app.js +12 -5
- package/dist/cli/tui/dialogs/path-listing.d.ts +43 -0
- package/dist/cli/tui/dialogs/path-listing.js +127 -0
- package/dist/cli/tui/dialogs/path-picker.d.ts +67 -0
- package/dist/cli/tui/dialogs/path-picker.js +423 -0
- package/dist/cli/tui/dialogs/text-screen.d.ts +6 -0
- package/dist/cli/tui/dialogs/text-screen.js +10 -3
- package/dist/cli/tui/frame.d.ts +7 -10
- package/dist/cli/tui/frame.js +19 -10
- package/dist/cli/tui/index.d.ts +4 -3
- package/dist/cli/tui/index.js +2 -1
- package/dist/cli/tui/list/list-screen.d.ts +14 -2
- package/dist/cli/tui/list/list-screen.js +68 -32
- package/dist/cli/tui/list/list-types.d.ts +8 -4
- package/dist/cli/tui/nav.d.ts +29 -0
- package/dist/cli/tui/nav.js +67 -0
- package/dist/cli/validate.d.ts +1 -1
- package/dist/cli/validate.js +3 -3
- package/dist/cli/version.d.ts +2 -0
- package/dist/cli/version.js +11 -0
- package/dist/core/config/defaults.js +5 -1
- package/dist/core/config/loader.js +12 -2
- package/dist/core/local-config/overrides.js +1 -0
- package/dist/core/prompt.d.ts +19 -0
- package/dist/core/prompt.js +43 -3
- package/dist/core/schema/common.d.ts +6 -0
- package/dist/core/schema/common.js +8 -0
- package/dist/core/schema/config.d.ts +23 -0
- package/dist/core/schema/config.js +10 -1
- package/dist/core/schema/harness.d.ts +1 -0
- package/dist/core/schema/harness.js +8 -2
- package/dist/core/schema/index.d.ts +3 -1
- package/dist/core/schema/index.js +3 -1
- package/dist/core/schema/profile.d.ts +1 -0
- package/dist/core/schema/profile.js +3 -0
- package/dist/core/schema/redact.d.ts +13 -0
- package/dist/core/schema/redact.js +75 -0
- package/dist/core/schema/sandbox.js +1 -0
- package/dist/core/schema/vpn.d.ts +17 -0
- package/dist/core/schema/vpn.js +22 -0
- package/dist/core/schema/web.d.ts +6 -0
- package/dist/core/schema/web.js +14 -0
- package/dist/core/types.d.ts +26 -0
- package/dist/guest/agents/agent-files.d.ts +49 -0
- package/dist/guest/agents/agent-files.js +63 -0
- package/dist/guest/agents/agent-installer.js +2 -9
- package/dist/guest/agents/local-state.d.ts +12 -0
- package/dist/guest/agents/local-state.js +198 -0
- package/dist/guest/agents/sbx-agent.d.ts +2 -0
- package/dist/guest/agents/sbx-agent.js +35 -0
- package/dist/guest/boot/boot.d.ts +4 -0
- package/dist/guest/boot/boot.js +50 -11
- package/dist/guest/daemon/daemon.js +4 -1
- package/dist/guest/daemon/exec.js +2 -1
- package/dist/guest/daemon/idle-shutdown.js +2 -0
- package/dist/guest/daemon/sessions.js +4 -1
- package/dist/guest/entries/agent.d.ts +1 -0
- package/dist/guest/entries/agent.js +10 -0
- package/dist/guest/entries/daemon.js +2 -0
- package/dist/guest/runtime/csc.d.ts +1 -0
- package/dist/guest/runtime/csc.js +1 -0
- package/dist/guest/runtime/secrets.d.ts +12 -0
- package/dist/guest/runtime/secrets.js +63 -0
- package/dist/guest/setup/claude-profile.d.ts +2 -1
- package/dist/guest/setup/claude-profile.js +12 -1
- package/dist/guest/setup/environment.d.ts +6 -0
- package/dist/guest/setup/environment.js +56 -6
- package/dist/guest/setup/path-plan.d.ts +32 -0
- package/dist/guest/setup/path-plan.js +67 -0
- package/dist/guest/setup/shell-path.d.ts +1 -0
- package/dist/guest/setup/shell-path.js +22 -0
- package/dist/guest/toolchains/languages/python.js +1 -1
- package/dist/guest/toolchains/runtimes.js +2 -2
- package/dist/guest/vpn/index.d.ts +1 -0
- package/dist/guest/vpn/index.js +1 -0
- package/dist/guest/vpn/openvpn.d.ts +9 -0
- package/dist/guest/vpn/openvpn.js +47 -0
- package/dist/guest/vpn/tunnel.d.ts +17 -0
- package/dist/guest/vpn/tunnel.js +78 -0
- package/dist/guest/vpn/vpn.d.ts +6 -0
- package/dist/guest/vpn/vpn.js +126 -0
- package/dist/host/channel/attach.d.ts +3 -1
- package/dist/host/channel/attach.js +1 -1
- package/dist/host/channel/channel.d.ts +7 -0
- package/dist/host/channel/channel.js +26 -2
- package/dist/host/health/acl-read.d.ts +17 -0
- package/dist/host/health/acl-read.js +45 -0
- package/dist/host/health/config-backup.d.ts +11 -0
- package/dist/host/health/config-backup.js +73 -0
- package/dist/host/health/index.d.ts +6 -0
- package/dist/host/health/index.js +7 -0
- package/dist/host/health/install-state.d.ts +33 -0
- package/dist/host/health/install-state.js +110 -0
- package/dist/host/health/path-copies.d.ts +32 -0
- package/dist/host/health/path-copies.js +82 -0
- package/dist/host/health/stale.d.ts +45 -0
- package/dist/host/health/stale.js +120 -0
- package/dist/host/health/system.d.ts +37 -0
- package/dist/host/health/system.js +87 -0
- package/dist/host/install/copies.d.ts +13 -0
- package/dist/host/install/copies.js +63 -0
- package/dist/host/install/index.d.ts +1 -0
- package/dist/host/install/index.js +1 -0
- package/dist/host/launch/generate.js +25 -1
- package/dist/host/launch/session-file.js +4 -1
- package/dist/host/launch/stage.js +1 -1
- package/dist/host/migrate/backup.js +3 -0
- package/dist/host/migrate/migrations/config-file.d.ts +2 -0
- package/dist/host/migrate/migrations/config-file.js +7 -0
- package/dist/host/migrate/migrations/follow-machine-storage.js +9 -1
- package/dist/host/migrate/migrations/pin-storage-root.d.ts +4 -0
- package/dist/host/migrate/migrations/pin-storage-root.js +46 -0
- package/dist/host/migrate/migrations/unpin-config-defaults.js +4 -1
- package/dist/host/migrate/registry.js +2 -1
- package/dist/host/profile/accounts.d.ts +25 -1
- package/dist/host/profile/accounts.js +96 -13
- package/dist/host/profile/agent-accounts.d.ts +5 -1
- package/dist/host/profile/agent-accounts.js +35 -5
- package/dist/host/profile/index.d.ts +2 -1
- package/dist/host/profile/index.js +1 -0
- package/dist/host/profile/plugin-share.d.ts +26 -0
- package/dist/host/profile/plugin-share.js +146 -0
- package/dist/host/projects/join.d.ts +7 -1
- package/dist/host/projects/join.js +21 -4
- package/dist/host/projects/registry.d.ts +16 -10
- package/dist/host/projects/registry.js +74 -6
- package/dist/host/sandbox/platform.d.ts +2 -0
- package/dist/host/sandbox/platform.js +21 -2
- package/dist/host/secrets/index.d.ts +2 -0
- package/dist/host/secrets/index.js +2 -0
- package/dist/host/secrets/launch-secrets.d.ts +17 -0
- package/dist/host/secrets/launch-secrets.js +93 -0
- package/dist/host/secrets/secret-store.d.ts +25 -0
- package/dist/host/secrets/secret-store.js +89 -0
- package/dist/host/sharing/acl.d.ts +16 -2
- package/dist/host/sharing/acl.js +35 -10
- package/dist/host/sharing/current.js +11 -2
- package/dist/host/sharing/doctor.d.ts +2 -0
- package/dist/host/sharing/doctor.js +44 -0
- package/dist/host/sharing/group-access.d.ts +6 -0
- package/dist/host/sharing/group-access.js +24 -0
- package/dist/host/sharing/index.d.ts +2 -1
- package/dist/host/sharing/index.js +2 -1
- package/dist/host/sharing/lifecycle.d.ts +8 -2
- package/dist/host/sharing/lifecycle.js +16 -7
- package/dist/host/storage/cleanup.d.ts +2 -0
- package/dist/host/storage/cleanup.js +2 -1
- package/dist/host/storage/history.d.ts +21 -0
- package/dist/host/storage/history.js +49 -0
- package/dist/host/storage/index.d.ts +4 -0
- package/dist/host/storage/index.js +4 -0
- package/dist/host/storage/move.d.ts +95 -0
- package/dist/host/storage/move.js +384 -0
- package/dist/host/storage/offer.d.ts +11 -0
- package/dist/host/storage/offer.js +36 -0
- package/dist/host/storage/root.d.ts +18 -0
- package/dist/host/storage/root.js +77 -0
- package/dist/host/tools/windows-terminal.d.ts +2 -0
- package/dist/host/tools/windows-terminal.js +23 -5
- package/dist/host/update/index.d.ts +1 -1
- package/dist/host/update/index.js +1 -1
- package/dist/host/update/notice.d.ts +2 -0
- package/dist/host/update/notice.js +13 -1
- package/dist/host/update/update-state.d.ts +6 -0
- package/dist/host/update/update-state.js +2 -0
- package/dist/host/update/updater.d.ts +19 -0
- package/dist/host/update/updater.js +88 -12
- package/dist/host/vpn/index.d.ts +4 -0
- package/dist/host/vpn/index.js +4 -0
- package/dist/host/vpn/login.d.ts +24 -0
- package/dist/host/vpn/login.js +79 -0
- package/dist/host/vpn/nordvpn.d.ts +21 -0
- package/dist/host/vpn/nordvpn.js +77 -0
- package/dist/host/vpn/prepare.d.ts +17 -0
- package/dist/host/vpn/prepare.js +77 -0
- package/dist/host/vpn/status.d.ts +12 -0
- package/dist/host/vpn/status.js +53 -0
- package/dist/host/web/auth.d.ts +38 -0
- package/dist/host/web/auth.js +96 -0
- package/dist/host/web/backend.d.ts +14 -0
- package/dist/host/web/backend.js +1 -0
- package/dist/host/web/bridge.d.ts +27 -0
- package/dist/host/web/bridge.js +144 -0
- package/dist/host/web/browser.d.ts +1 -0
- package/dist/host/web/browser.js +10 -0
- package/dist/host/web/control.d.ts +17 -0
- package/dist/host/web/control.js +67 -0
- package/dist/host/web/index.d.ts +9 -0
- package/dist/host/web/index.js +8 -0
- package/dist/host/web/runner.d.ts +14 -0
- package/dist/host/web/runner.js +45 -0
- package/dist/host/web/server.d.ts +40 -0
- package/dist/host/web/server.js +218 -0
- package/dist/host/web/state.d.ts +20 -0
- package/dist/host/web/state.js +41 -0
- package/dist/host/web/static-files.d.ts +13 -0
- package/dist/host/web/static-files.js +57 -0
- package/dist/runtime/agent.js +27614 -0
- package/dist/runtime/daemon.js +1012 -618
- package/dist/runtime/db.js +236 -106
- package/dist/runtime/main.js +1093 -250
- package/dist/runtime/netproxy.js +102 -3
- package/dist/runtime/view.js +102 -3
- package/dist/selftest/accounts.test.js +40 -0
- package/dist/selftest/agent-paths.test.d.ts +2 -0
- package/dist/selftest/agent-paths.test.js +115 -0
- package/dist/selftest/channel.test.js +5 -0
- package/dist/selftest/cli.test.js +34 -4
- package/dist/selftest/credentials.test.d.ts +2 -0
- package/dist/selftest/credentials.test.js +198 -0
- package/dist/selftest/generate.test.js +1 -1
- package/dist/selftest/health.test.d.ts +2 -0
- package/dist/selftest/health.test.js +470 -0
- package/dist/selftest/host-sim.test.js +2 -0
- package/dist/selftest/index.js +19 -0
- package/dist/selftest/layout.test.js +2 -0
- package/dist/selftest/menu-screens.d.ts +7 -0
- package/dist/selftest/menu-screens.js +65 -16
- package/dist/selftest/menu.test.js +574 -21
- package/dist/selftest/migrate.test.js +1 -1
- package/dist/selftest/personalization.test.js +3 -1
- package/dist/selftest/projects.test.js +39 -1
- package/dist/selftest/shared-use.test.js +64 -2
- package/dist/selftest/sharing.test.js +50 -1
- package/dist/selftest/storage.test.d.ts +2 -0
- package/dist/selftest/storage.test.js +363 -0
- package/dist/selftest/support/fixtures.d.ts +14 -0
- package/dist/selftest/support/releases.js +1 -1
- package/dist/selftest/toolchains.test.js +21 -0
- package/dist/selftest/update-service.test.js +87 -3
- package/dist/selftest/vpn.test.d.ts +2 -0
- package/dist/selftest/vpn.test.js +279 -0
- package/dist/selftest/web.test.d.ts +2 -0
- package/dist/selftest/web.test.js +304 -0
- package/dist/shared/apps/catalogue.js +31 -0
- package/dist/shared/channel/index.d.ts +1 -0
- package/dist/shared/channel/index.js +1 -0
- package/dist/shared/channel/run-dir.d.ts +6 -1
- package/dist/shared/channel/run-dir.js +12 -1
- package/dist/shared/channel/schema.d.ts +19 -0
- package/dist/shared/channel/schema.js +11 -0
- package/dist/shared/channel/secrets.d.ts +28 -0
- package/dist/shared/channel/secrets.js +44 -0
- package/dist/shared/vpn/download.d.ts +13 -0
- package/dist/shared/vpn/download.js +14 -0
- package/dist/shared/vpn/kill-switch.d.ts +18 -0
- package/dist/shared/vpn/kill-switch.js +81 -0
- package/dist/shared/vpn/ovpn.d.ts +23 -0
- package/dist/shared/vpn/ovpn.js +244 -0
- package/dist/shared/web/index.d.ts +1 -0
- package/dist/shared/web/index.js +1 -0
- package/dist/shared/web/protocol.d.ts +61 -0
- package/dist/shared/web/protocol.js +35 -0
- package/dist/sync/sync-cycle.js +5 -1
- package/dist/sync/sync-state.d.ts +1 -0
- package/dist/sync/sync-state.js +1 -0
- package/dist/sync/watcher.js +10 -0
- package/dist/web/index.html +13 -0
- package/dist/web/main-CXESL347.js +45 -0
- package/dist/web/main-VLR7DVQ4.css +1 -0
- package/native/csharp/FolderSecurity.cs +29 -0
- package/native/scripts/protect-data.ps1 +29 -0
- package/native/scripts/read-folder-sddl.ps1 +10 -0
- package/native/scripts/set-folder-access.ps1 +49 -7
- package/node_modules/ws/LICENSE +20 -0
- package/node_modules/ws/README.md +548 -0
- package/node_modules/ws/browser.js +8 -0
- package/node_modules/ws/index.js +22 -0
- package/node_modules/ws/lib/buffer-util.js +131 -0
- package/node_modules/ws/lib/constants.js +19 -0
- package/node_modules/ws/lib/event-target.js +292 -0
- package/node_modules/ws/lib/extension.js +203 -0
- package/node_modules/ws/lib/limiter.js +55 -0
- package/node_modules/ws/lib/permessage-deflate.js +530 -0
- package/node_modules/ws/lib/receiver.js +743 -0
- package/node_modules/ws/lib/sender.js +607 -0
- package/node_modules/ws/lib/stream.js +161 -0
- package/node_modules/ws/lib/subprotocol.js +62 -0
- package/node_modules/ws/lib/validation.js +152 -0
- package/node_modules/ws/lib/websocket-server.js +562 -0
- package/node_modules/ws/lib/websocket.js +1421 -0
- package/node_modules/ws/package.json +74 -0
- package/node_modules/ws/wrapper.mjs +21 -0
- package/package.json +15 -5
- package/sandbox/csharp/EnvBroadcast.cs +33 -0
- package/sandbox/csharp/PathSync.cs +90 -0
- package/sandbox/scripts/install-shell-path.ps1 +73 -0
- package/sandbox/scripts/set-machine-environment.ps1 +37 -4
- package/schemas/config.schema.json +79 -4
- package/schemas/sandbox-config.schema.json +14 -1
- package/dist/cli/commands/repair/checks.d.ts +0 -2
- package/dist/cli/commands/repair/checks.js +0 -246
- package/dist/cli/menu/pages/start-page.d.ts +0 -43
- package/dist/cli/menu/pages/start-page.js +0 -192
- package/dist/cli/tui/tab-bar.d.ts +0 -9
- package/dist/cli/tui/tab-bar.js +0 -33
package/dist/runtime/netproxy.js
CHANGED
|
@@ -25328,6 +25328,9 @@ function enabled(what, markers) {
|
|
|
25328
25328
|
function Packages(what, example) {
|
|
25329
25329
|
return StringsSchema.describe(what + ", installed once and kept (e.g. " + example + ").");
|
|
25330
25330
|
}
|
|
25331
|
+
function secret(schema) {
|
|
25332
|
+
return schema.meta({ secret: true });
|
|
25333
|
+
}
|
|
25331
25334
|
|
|
25332
25335
|
// src/core/schema/config.ts
|
|
25333
25336
|
var import_lodash = __toESM(require_lodash(), 1);
|
|
@@ -25396,10 +25399,15 @@ var HarnessSchema = external_exports.strictObject({
|
|
|
25396
25399
|
uvPackage: external_exports.string().optional().describe("Python package installed with `uv tool install` inside the sandbox (e.g. aider-chat)."),
|
|
25397
25400
|
uvBin: external_exports.string().optional().describe("Command the uv package provides."),
|
|
25398
25401
|
arguments: StringsSchema.describe("Arguments always passed to the agent."),
|
|
25399
|
-
environment: external_exports.record(external_exports.string(), external_exports.string()).describe(
|
|
25402
|
+
environment: external_exports.record(external_exports.string(), secret(external_exports.string())).describe(
|
|
25403
|
+
"Environment variables for the agent (API keys go here). Their values are shown as *** and are handed to the sandbox in a one-shot file, never kept in the launch folder. The agent can read its own environment."
|
|
25404
|
+
),
|
|
25400
25405
|
home: HarnessHomeSchema.optional().describe(
|
|
25401
25406
|
"Where its login lives inside the sandbox; leave out when the agent cannot be pointed at a folder (then its login is not kept between sandboxes)."
|
|
25402
25407
|
),
|
|
25408
|
+
localState: external_exports.record(external_exports.string().regex(/^[A-Za-z_][A-Za-z0-9_]*$/), SubfolderSchema).optional().describe(
|
|
25409
|
+
"Environment variable -> folder below the agent's own state folder (state\\<agent>) for SQLite databases. SQLite cannot run in a mapped folder, so the agent runs from a copy on the sandbox's disk (the variable points to it) that is copied from and back to that folder."
|
|
25410
|
+
),
|
|
25403
25411
|
resumeArguments: StringsSchema.optional().describe(
|
|
25404
25412
|
"Arguments used when the agent is restarted in place (e.g. after an account switch) so it resumes the conversation."
|
|
25405
25413
|
),
|
|
@@ -25451,6 +25459,9 @@ var ClaudeProfileSchema = external_exports.strictObject({
|
|
|
25451
25459
|
globalStateFile: external_exports.string().describe('Your .claude.json, or "auto". Empty string = do not copy.'),
|
|
25452
25460
|
copyCredentials: external_exports.boolean().describe("Copy your Claude LOGIN into the sandbox. Prefer sandbox account instead."),
|
|
25453
25461
|
overwrite: external_exports.boolean().describe("Refresh these settings from this PC on every launch."),
|
|
25462
|
+
sharePluginsAcrossAccounts: external_exports.boolean().describe(
|
|
25463
|
+
"When you switch Claude accounts, copy your Claude plugins (and which ones are enabled) into a data set that has none yet. Off by default: plugins are code that runs in your sessions."
|
|
25464
|
+
),
|
|
25454
25465
|
syncHistory: external_exports.boolean().describe("Bring conversation history in, and sync new history back (path-translated)."),
|
|
25455
25466
|
historyScope: external_exports.enum(["project", "all"]).describe(
|
|
25456
25467
|
`Which history comes in: "project" = only the projects in this sandbox (other projects' conversations, file backups and prompts stay on this PC), "all" = everything. Only this sandbox's projects ever sync back.`
|
|
@@ -25527,7 +25538,10 @@ var NetworkSchema = external_exports.strictObject({
|
|
|
25527
25538
|
"Reach servers in the sandbox from this PC: http://localhost:<pc> here goes to <sandbox> inside, while it runs. Nothing else on your network can use them."
|
|
25528
25539
|
),
|
|
25529
25540
|
dns: external_exports.array(external_exports.string().regex(/^\d{1,3}(\.\d{1,3}){3}$/, "an IPv4 address like 1.1.1.1")).describe("DNS servers for the sandbox instead of your network's, e.g. 1.1.1.1 and 9.9.9.9."),
|
|
25530
|
-
proxy: external_exports.string().regex(/^(https?:\/\/[^\s]+)?$/, "http://host:port").
|
|
25541
|
+
proxy: external_exports.string().regex(/^(https?:\/\/[^\s]+)?$/, "http://host:port").refine(
|
|
25542
|
+
(v) => !/^https?:\/\/[^/?#]*@/i.test(v),
|
|
25543
|
+
"no user name or password in the address (it would be stored in plain text and visible to the agent): use a proxy that needs no login"
|
|
25544
|
+
).describe(
|
|
25531
25545
|
"An HTTP proxy the sandbox uses to reach the internet (HTTP_PROXY / HTTPS_PROXY for everything in it), e.g. http://proxy.corp:8080. Empty = none."
|
|
25532
25546
|
)
|
|
25533
25547
|
});
|
|
@@ -25929,6 +25943,17 @@ var APPS = [
|
|
|
25929
25943
|
exe: "lazygit.exe",
|
|
25930
25944
|
cli: true
|
|
25931
25945
|
},
|
|
25946
|
+
{
|
|
25947
|
+
id: "jj",
|
|
25948
|
+
name: "Jujutsu (jj)",
|
|
25949
|
+
category: "git",
|
|
25950
|
+
about: "Git-compatible version control; conflicts do not block a rebase. Pilot, untested with worktrees.",
|
|
25951
|
+
size: "10 MB",
|
|
25952
|
+
source: gh("jj-vcs/jj", "^jj-v[\\d.]+-x86_64-pc-windows-msvc\\.zip$"),
|
|
25953
|
+
exe: "jj.exe",
|
|
25954
|
+
cli: true,
|
|
25955
|
+
fullGitOnly: true
|
|
25956
|
+
},
|
|
25932
25957
|
// ---- utilities
|
|
25933
25958
|
{
|
|
25934
25959
|
id: "7zip",
|
|
@@ -26457,6 +26482,26 @@ var APPS = [
|
|
|
26457
26482
|
source: gh("gitleaks/gitleaks", "^gitleaks_[\\d.]+_windows_x64\\.zip$"),
|
|
26458
26483
|
exe: "gitleaks.exe",
|
|
26459
26484
|
cli: true
|
|
26485
|
+
},
|
|
26486
|
+
{
|
|
26487
|
+
id: "ast-grep",
|
|
26488
|
+
name: "ast-grep",
|
|
26489
|
+
category: "cli",
|
|
26490
|
+
about: "Search and rewrite code by its syntax tree (ast-grep, sg); prints only the matches.",
|
|
26491
|
+
size: "15 MB",
|
|
26492
|
+
source: gh("ast-grep/ast-grep", "^app-x86_64-pc-windows-msvc\\.zip$"),
|
|
26493
|
+
exe: "ast-grep.exe",
|
|
26494
|
+
cli: true
|
|
26495
|
+
},
|
|
26496
|
+
{
|
|
26497
|
+
id: "rust-analyzer",
|
|
26498
|
+
name: "rust-analyzer",
|
|
26499
|
+
category: "cli",
|
|
26500
|
+
about: "Rust language server: type errors and go-to-definition without cargo (for editors and the Claude LSP plugin).",
|
|
26501
|
+
size: "18 MB",
|
|
26502
|
+
source: gh("rust-lang/rust-analyzer", "^rust-analyzer-x86_64-pc-windows-msvc\\.zip$"),
|
|
26503
|
+
exe: "rust-analyzer.exe",
|
|
26504
|
+
cli: true
|
|
26460
26505
|
}
|
|
26461
26506
|
];
|
|
26462
26507
|
|
|
@@ -26525,6 +26570,33 @@ var ResumeSchema = external_exports.strictObject({
|
|
|
26525
26570
|
)
|
|
26526
26571
|
});
|
|
26527
26572
|
|
|
26573
|
+
// src/core/schema/web.ts
|
|
26574
|
+
var WebSchema = external_exports.strictObject({
|
|
26575
|
+
enabled: external_exports.boolean().describe(
|
|
26576
|
+
"(Beta) Allow the web UI: your sandbox sessions in a browser on this PC. Off by default, and nothing starts it by itself yet: sandbox web start works either way and runs it until sandbox web stop (or a restart of the PC)."
|
|
26577
|
+
),
|
|
26578
|
+
port: external_exports.number().int().min(1024).max(65535).describe("Port of the web UI on 127.0.0.1 (this PC only). Pick another when it is taken.")
|
|
26579
|
+
});
|
|
26580
|
+
|
|
26581
|
+
// src/core/schema/vpn.ts
|
|
26582
|
+
var VPN_PROVIDERS = ["nordvpn", "openvpn-file"];
|
|
26583
|
+
var VpnSchema = external_exports.strictObject({
|
|
26584
|
+
enabled: external_exports.boolean().describe(
|
|
26585
|
+
"Send the sandbox's traffic through a VPN. Only the sandbox: your PC's own connection is untouched. Needs a saved login first (sandbox vpn login). The agent in the sandbox can read that login and can turn the tunnel off (it is the administrator there)."
|
|
26586
|
+
),
|
|
26587
|
+
provider: external_exports.enum(VPN_PROVIDERS).describe(
|
|
26588
|
+
"nordvpn: a recommended NordVPN server is picked at every launch. openvpn-file: your own .ovpn file (configFile)."
|
|
26589
|
+
),
|
|
26590
|
+
protocol: external_exports.enum(["udp", "tcp"]).describe("udp is faster; tcp gets through networks that block udp."),
|
|
26591
|
+
country: external_exports.string().regex(/^([A-Za-z][A-Za-z .'-]{0,39})?$/, "a country name or code like uk or Germany").describe("nordvpn: the country of the server, e.g. uk, us or Germany. Empty = the best server anywhere."),
|
|
26592
|
+
configFile: external_exports.string().describe(
|
|
26593
|
+
"openvpn-file: the .ovpn file on this PC (its certificates inside it). Files that run programs (script-security, up, down, plugin ...) are refused. A project's file can never set this."
|
|
26594
|
+
),
|
|
26595
|
+
killSwitch: external_exports.boolean().describe(
|
|
26596
|
+
"Block all traffic that does not go through the tunnel: when the tunnel cannot start, the sandbox stays offline instead of using your normal connection. A project can only turn this on, never off."
|
|
26597
|
+
)
|
|
26598
|
+
});
|
|
26599
|
+
|
|
26528
26600
|
// src/core/schema/config.ts
|
|
26529
26601
|
var ConfigSchema = external_exports.strictObject({
|
|
26530
26602
|
$schema: SchemaRefSchema.optional(),
|
|
@@ -26537,7 +26609,9 @@ var ConfigSchema = external_exports.strictObject({
|
|
|
26537
26609
|
sandbox: SandboxSchema,
|
|
26538
26610
|
sharing: SharingSchema,
|
|
26539
26611
|
storage: external_exports.strictObject({
|
|
26540
|
-
root: external_exports.string().min(1).describe(
|
|
26612
|
+
root: external_exports.string().min(1).describe(
|
|
26613
|
+
"Where everything is kept on this PC (tools, databases, logins, launches). The default is a private folder for you under %ProgramData%\\AgentSandbox\\users, which works for installs for one user and for everyone. sandbox storage move <folder> moves it."
|
|
26614
|
+
),
|
|
26541
26615
|
persistAgentState: external_exports.boolean().describe("Keep agent logins and history between sandboxes."),
|
|
26542
26616
|
dataName: NameSchema.describe("Name of the persistent data set (C:\\AgentData) shared by all workspaces."),
|
|
26543
26617
|
markSandboxFiles: external_exports.boolean().describe(
|
|
@@ -26548,6 +26622,7 @@ var ConfigSchema = external_exports.strictObject({
|
|
|
26548
26622
|
)
|
|
26549
26623
|
}),
|
|
26550
26624
|
network: NetworkSchema,
|
|
26625
|
+
vpn: VpnSchema,
|
|
26551
26626
|
provisioning: ProvisioningSchema,
|
|
26552
26627
|
downloads: DownloadsSchema,
|
|
26553
26628
|
toolchains: ToolchainsSchema,
|
|
@@ -26555,6 +26630,7 @@ var ConfigSchema = external_exports.strictObject({
|
|
|
26555
26630
|
"Databases running inside the sandbox. Data persists in C:\\AgentData\\databases; each one starts at boot."
|
|
26556
26631
|
),
|
|
26557
26632
|
attach: AttachSchema,
|
|
26633
|
+
web: WebSchema,
|
|
26558
26634
|
agentCommands: AgentCommandsSchema,
|
|
26559
26635
|
secrets: SecretsSchema,
|
|
26560
26636
|
personalization: toggle("Copy your desktop look (theme, accent, taskbar, wallpaper, ...) into the sandbox."),
|
|
@@ -26587,6 +26663,8 @@ var LocalOverridesSchema = external_exports.strictObject({
|
|
|
26587
26663
|
sandbox: SandboxSchema.omit({ cpuLimit: true, pageFileMb: true }).partial(),
|
|
26588
26664
|
// A project may block more (the LAN, hosts); it never opens hosts, ports, DNS or a proxy.
|
|
26589
26665
|
network: NetworkSchema.pick({ blockPrivateRanges: true, blockHosts: true }).partial(),
|
|
26666
|
+
// A project may turn the kill switch on, never off, and never choose a VPN, a server, a file or a login.
|
|
26667
|
+
vpn: VpnSchema.pick({ killSwitch: true }).partial(),
|
|
26590
26668
|
provisioning: ProvisioningSchema.pick({ copyFromHost: true, fallbackToInstall: true, refresh: true }).extend({ git: GitSchema.partial(), terminal: toggle("Windows Terminal as the sandbox window.").partial() }).partial(),
|
|
26591
26669
|
downloads: DownloadsSchema.partial(),
|
|
26592
26670
|
// Every toolchain setting, each one optional (a project usually only switches languages on or pins a version).
|
|
@@ -26727,6 +26805,16 @@ var ProjectStatusSchema = external_exports.object({
|
|
|
26727
26805
|
databases: external_exports.array(external_exports.object({ database: Text(32), port: external_exports.number().int() })).max(16),
|
|
26728
26806
|
summary: external_exports.array(Text(512)).max(64)
|
|
26729
26807
|
});
|
|
26808
|
+
var VpnStatusSchema = external_exports.object({
|
|
26809
|
+
state: external_exports.enum(["off", "starting", "up", "failed"]),
|
|
26810
|
+
message: Text(2e3),
|
|
26811
|
+
killSwitch: external_exports.boolean(),
|
|
26812
|
+
/** The server's name, e.g. uk2201.nordvpn.com. */
|
|
26813
|
+
server: Text(128).optional(),
|
|
26814
|
+
/** What the sandbox's traffic looks like from outside, once the tunnel is up. */
|
|
26815
|
+
publicIp: Text(64).optional(),
|
|
26816
|
+
updatedAt: TimeSchema
|
|
26817
|
+
});
|
|
26730
26818
|
|
|
26731
26819
|
// src/shared/io/json.ts
|
|
26732
26820
|
import fs2 from "node:fs";
|
|
@@ -26861,20 +26949,25 @@ var scan = (schema, dir) => {
|
|
|
26861
26949
|
var RunDir = class {
|
|
26862
26950
|
root;
|
|
26863
26951
|
sandboxFile;
|
|
26952
|
+
vpnFile;
|
|
26864
26953
|
requestsDir;
|
|
26865
26954
|
responsesDir;
|
|
26866
26955
|
sessionsDir;
|
|
26867
26956
|
projectsDir;
|
|
26868
26957
|
/** audit.processes: programs the sandbox started, in small .jsonl files the host takes in and deletes. */
|
|
26869
26958
|
auditDir;
|
|
26959
|
+
/** One-shot secrets the host hands over (see secrets.ts). Next to run, not in it: shared-use users can change run. */
|
|
26960
|
+
secretsDir;
|
|
26870
26961
|
constructor(dataDir2) {
|
|
26871
26962
|
this.root = path3.join(dataDir2, "run");
|
|
26872
26963
|
this.sandboxFile = path3.join(this.root, "sandbox.json");
|
|
26964
|
+
this.vpnFile = path3.join(this.root, "vpn.json");
|
|
26873
26965
|
this.requestsDir = path3.join(this.root, "requests");
|
|
26874
26966
|
this.responsesDir = path3.join(this.root, "responses");
|
|
26875
26967
|
this.sessionsDir = path3.join(this.root, "sessions");
|
|
26876
26968
|
this.projectsDir = path3.join(this.root, "projects");
|
|
26877
26969
|
this.auditDir = path3.join(this.root, "audit");
|
|
26970
|
+
this.secretsDir = path3.join(dataDir2, "secrets");
|
|
26878
26971
|
}
|
|
26879
26972
|
requestFile(id) {
|
|
26880
26973
|
return path3.join(this.requestsDir, safeId(id) + ".json");
|
|
@@ -26888,9 +26981,15 @@ var RunDir = class {
|
|
|
26888
26981
|
projectFile(name) {
|
|
26889
26982
|
return path3.join(this.projectsDir, safeId(name) + ".json");
|
|
26890
26983
|
}
|
|
26984
|
+
secretFile(id) {
|
|
26985
|
+
return path3.join(this.secretsDir, safeId(id) + ".json");
|
|
26986
|
+
}
|
|
26891
26987
|
readSandboxStatus() {
|
|
26892
26988
|
return readValid(SandboxStatusSchema, this.sandboxFile);
|
|
26893
26989
|
}
|
|
26990
|
+
readVpnStatus() {
|
|
26991
|
+
return readValid(VpnStatusSchema, this.vpnFile);
|
|
26992
|
+
}
|
|
26894
26993
|
readSession(id) {
|
|
26895
26994
|
return readValid(SessionStatusSchema, this.sessionFile(id));
|
|
26896
26995
|
}
|
package/dist/runtime/view.js
CHANGED
|
@@ -25665,6 +25665,9 @@ function enabled(what, markers) {
|
|
|
25665
25665
|
function Packages(what, example) {
|
|
25666
25666
|
return StringsSchema.describe(what + ", installed once and kept (e.g. " + example + ").");
|
|
25667
25667
|
}
|
|
25668
|
+
function secret(schema) {
|
|
25669
|
+
return schema.meta({ secret: true });
|
|
25670
|
+
}
|
|
25668
25671
|
|
|
25669
25672
|
// src/core/schema/config.ts
|
|
25670
25673
|
var import_lodash = __toESM(require_lodash(), 1);
|
|
@@ -25733,10 +25736,15 @@ var HarnessSchema = external_exports.strictObject({
|
|
|
25733
25736
|
uvPackage: external_exports.string().optional().describe("Python package installed with `uv tool install` inside the sandbox (e.g. aider-chat)."),
|
|
25734
25737
|
uvBin: external_exports.string().optional().describe("Command the uv package provides."),
|
|
25735
25738
|
arguments: StringsSchema.describe("Arguments always passed to the agent."),
|
|
25736
|
-
environment: external_exports.record(external_exports.string(), external_exports.string()).describe(
|
|
25739
|
+
environment: external_exports.record(external_exports.string(), secret(external_exports.string())).describe(
|
|
25740
|
+
"Environment variables for the agent (API keys go here). Their values are shown as *** and are handed to the sandbox in a one-shot file, never kept in the launch folder. The agent can read its own environment."
|
|
25741
|
+
),
|
|
25737
25742
|
home: HarnessHomeSchema.optional().describe(
|
|
25738
25743
|
"Where its login lives inside the sandbox; leave out when the agent cannot be pointed at a folder (then its login is not kept between sandboxes)."
|
|
25739
25744
|
),
|
|
25745
|
+
localState: external_exports.record(external_exports.string().regex(/^[A-Za-z_][A-Za-z0-9_]*$/), SubfolderSchema).optional().describe(
|
|
25746
|
+
"Environment variable -> folder below the agent's own state folder (state\\<agent>) for SQLite databases. SQLite cannot run in a mapped folder, so the agent runs from a copy on the sandbox's disk (the variable points to it) that is copied from and back to that folder."
|
|
25747
|
+
),
|
|
25740
25748
|
resumeArguments: StringsSchema.optional().describe(
|
|
25741
25749
|
"Arguments used when the agent is restarted in place (e.g. after an account switch) so it resumes the conversation."
|
|
25742
25750
|
),
|
|
@@ -25788,6 +25796,9 @@ var ClaudeProfileSchema = external_exports.strictObject({
|
|
|
25788
25796
|
globalStateFile: external_exports.string().describe('Your .claude.json, or "auto". Empty string = do not copy.'),
|
|
25789
25797
|
copyCredentials: external_exports.boolean().describe("Copy your Claude LOGIN into the sandbox. Prefer sandbox account instead."),
|
|
25790
25798
|
overwrite: external_exports.boolean().describe("Refresh these settings from this PC on every launch."),
|
|
25799
|
+
sharePluginsAcrossAccounts: external_exports.boolean().describe(
|
|
25800
|
+
"When you switch Claude accounts, copy your Claude plugins (and which ones are enabled) into a data set that has none yet. Off by default: plugins are code that runs in your sessions."
|
|
25801
|
+
),
|
|
25791
25802
|
syncHistory: external_exports.boolean().describe("Bring conversation history in, and sync new history back (path-translated)."),
|
|
25792
25803
|
historyScope: external_exports.enum(["project", "all"]).describe(
|
|
25793
25804
|
`Which history comes in: "project" = only the projects in this sandbox (other projects' conversations, file backups and prompts stay on this PC), "all" = everything. Only this sandbox's projects ever sync back.`
|
|
@@ -25864,7 +25875,10 @@ var NetworkSchema = external_exports.strictObject({
|
|
|
25864
25875
|
"Reach servers in the sandbox from this PC: http://localhost:<pc> here goes to <sandbox> inside, while it runs. Nothing else on your network can use them."
|
|
25865
25876
|
),
|
|
25866
25877
|
dns: external_exports.array(external_exports.string().regex(/^\d{1,3}(\.\d{1,3}){3}$/, "an IPv4 address like 1.1.1.1")).describe("DNS servers for the sandbox instead of your network's, e.g. 1.1.1.1 and 9.9.9.9."),
|
|
25867
|
-
proxy: external_exports.string().regex(/^(https?:\/\/[^\s]+)?$/, "http://host:port").
|
|
25878
|
+
proxy: external_exports.string().regex(/^(https?:\/\/[^\s]+)?$/, "http://host:port").refine(
|
|
25879
|
+
(v) => !/^https?:\/\/[^/?#]*@/i.test(v),
|
|
25880
|
+
"no user name or password in the address (it would be stored in plain text and visible to the agent): use a proxy that needs no login"
|
|
25881
|
+
).describe(
|
|
25868
25882
|
"An HTTP proxy the sandbox uses to reach the internet (HTTP_PROXY / HTTPS_PROXY for everything in it), e.g. http://proxy.corp:8080. Empty = none."
|
|
25869
25883
|
)
|
|
25870
25884
|
});
|
|
@@ -26266,6 +26280,17 @@ var APPS = [
|
|
|
26266
26280
|
exe: "lazygit.exe",
|
|
26267
26281
|
cli: true
|
|
26268
26282
|
},
|
|
26283
|
+
{
|
|
26284
|
+
id: "jj",
|
|
26285
|
+
name: "Jujutsu (jj)",
|
|
26286
|
+
category: "git",
|
|
26287
|
+
about: "Git-compatible version control; conflicts do not block a rebase. Pilot, untested with worktrees.",
|
|
26288
|
+
size: "10 MB",
|
|
26289
|
+
source: gh("jj-vcs/jj", "^jj-v[\\d.]+-x86_64-pc-windows-msvc\\.zip$"),
|
|
26290
|
+
exe: "jj.exe",
|
|
26291
|
+
cli: true,
|
|
26292
|
+
fullGitOnly: true
|
|
26293
|
+
},
|
|
26269
26294
|
// ---- utilities
|
|
26270
26295
|
{
|
|
26271
26296
|
id: "7zip",
|
|
@@ -26794,6 +26819,26 @@ var APPS = [
|
|
|
26794
26819
|
source: gh("gitleaks/gitleaks", "^gitleaks_[\\d.]+_windows_x64\\.zip$"),
|
|
26795
26820
|
exe: "gitleaks.exe",
|
|
26796
26821
|
cli: true
|
|
26822
|
+
},
|
|
26823
|
+
{
|
|
26824
|
+
id: "ast-grep",
|
|
26825
|
+
name: "ast-grep",
|
|
26826
|
+
category: "cli",
|
|
26827
|
+
about: "Search and rewrite code by its syntax tree (ast-grep, sg); prints only the matches.",
|
|
26828
|
+
size: "15 MB",
|
|
26829
|
+
source: gh("ast-grep/ast-grep", "^app-x86_64-pc-windows-msvc\\.zip$"),
|
|
26830
|
+
exe: "ast-grep.exe",
|
|
26831
|
+
cli: true
|
|
26832
|
+
},
|
|
26833
|
+
{
|
|
26834
|
+
id: "rust-analyzer",
|
|
26835
|
+
name: "rust-analyzer",
|
|
26836
|
+
category: "cli",
|
|
26837
|
+
about: "Rust language server: type errors and go-to-definition without cargo (for editors and the Claude LSP plugin).",
|
|
26838
|
+
size: "18 MB",
|
|
26839
|
+
source: gh("rust-lang/rust-analyzer", "^rust-analyzer-x86_64-pc-windows-msvc\\.zip$"),
|
|
26840
|
+
exe: "rust-analyzer.exe",
|
|
26841
|
+
cli: true
|
|
26797
26842
|
}
|
|
26798
26843
|
];
|
|
26799
26844
|
|
|
@@ -26862,6 +26907,33 @@ var ResumeSchema = external_exports.strictObject({
|
|
|
26862
26907
|
)
|
|
26863
26908
|
});
|
|
26864
26909
|
|
|
26910
|
+
// src/core/schema/web.ts
|
|
26911
|
+
var WebSchema = external_exports.strictObject({
|
|
26912
|
+
enabled: external_exports.boolean().describe(
|
|
26913
|
+
"(Beta) Allow the web UI: your sandbox sessions in a browser on this PC. Off by default, and nothing starts it by itself yet: sandbox web start works either way and runs it until sandbox web stop (or a restart of the PC)."
|
|
26914
|
+
),
|
|
26915
|
+
port: external_exports.number().int().min(1024).max(65535).describe("Port of the web UI on 127.0.0.1 (this PC only). Pick another when it is taken.")
|
|
26916
|
+
});
|
|
26917
|
+
|
|
26918
|
+
// src/core/schema/vpn.ts
|
|
26919
|
+
var VPN_PROVIDERS = ["nordvpn", "openvpn-file"];
|
|
26920
|
+
var VpnSchema = external_exports.strictObject({
|
|
26921
|
+
enabled: external_exports.boolean().describe(
|
|
26922
|
+
"Send the sandbox's traffic through a VPN. Only the sandbox: your PC's own connection is untouched. Needs a saved login first (sandbox vpn login). The agent in the sandbox can read that login and can turn the tunnel off (it is the administrator there)."
|
|
26923
|
+
),
|
|
26924
|
+
provider: external_exports.enum(VPN_PROVIDERS).describe(
|
|
26925
|
+
"nordvpn: a recommended NordVPN server is picked at every launch. openvpn-file: your own .ovpn file (configFile)."
|
|
26926
|
+
),
|
|
26927
|
+
protocol: external_exports.enum(["udp", "tcp"]).describe("udp is faster; tcp gets through networks that block udp."),
|
|
26928
|
+
country: external_exports.string().regex(/^([A-Za-z][A-Za-z .'-]{0,39})?$/, "a country name or code like uk or Germany").describe("nordvpn: the country of the server, e.g. uk, us or Germany. Empty = the best server anywhere."),
|
|
26929
|
+
configFile: external_exports.string().describe(
|
|
26930
|
+
"openvpn-file: the .ovpn file on this PC (its certificates inside it). Files that run programs (script-security, up, down, plugin ...) are refused. A project's file can never set this."
|
|
26931
|
+
),
|
|
26932
|
+
killSwitch: external_exports.boolean().describe(
|
|
26933
|
+
"Block all traffic that does not go through the tunnel: when the tunnel cannot start, the sandbox stays offline instead of using your normal connection. A project can only turn this on, never off."
|
|
26934
|
+
)
|
|
26935
|
+
});
|
|
26936
|
+
|
|
26865
26937
|
// src/core/schema/config.ts
|
|
26866
26938
|
var ConfigSchema = external_exports.strictObject({
|
|
26867
26939
|
$schema: SchemaRefSchema.optional(),
|
|
@@ -26874,7 +26946,9 @@ var ConfigSchema = external_exports.strictObject({
|
|
|
26874
26946
|
sandbox: SandboxSchema,
|
|
26875
26947
|
sharing: SharingSchema,
|
|
26876
26948
|
storage: external_exports.strictObject({
|
|
26877
|
-
root: external_exports.string().min(1).describe(
|
|
26949
|
+
root: external_exports.string().min(1).describe(
|
|
26950
|
+
"Where everything is kept on this PC (tools, databases, logins, launches). The default is a private folder for you under %ProgramData%\\AgentSandbox\\users, which works for installs for one user and for everyone. sandbox storage move <folder> moves it."
|
|
26951
|
+
),
|
|
26878
26952
|
persistAgentState: external_exports.boolean().describe("Keep agent logins and history between sandboxes."),
|
|
26879
26953
|
dataName: NameSchema.describe("Name of the persistent data set (C:\\AgentData) shared by all workspaces."),
|
|
26880
26954
|
markSandboxFiles: external_exports.boolean().describe(
|
|
@@ -26885,6 +26959,7 @@ var ConfigSchema = external_exports.strictObject({
|
|
|
26885
26959
|
)
|
|
26886
26960
|
}),
|
|
26887
26961
|
network: NetworkSchema,
|
|
26962
|
+
vpn: VpnSchema,
|
|
26888
26963
|
provisioning: ProvisioningSchema,
|
|
26889
26964
|
downloads: DownloadsSchema,
|
|
26890
26965
|
toolchains: ToolchainsSchema,
|
|
@@ -26892,6 +26967,7 @@ var ConfigSchema = external_exports.strictObject({
|
|
|
26892
26967
|
"Databases running inside the sandbox. Data persists in C:\\AgentData\\databases; each one starts at boot."
|
|
26893
26968
|
),
|
|
26894
26969
|
attach: AttachSchema,
|
|
26970
|
+
web: WebSchema,
|
|
26895
26971
|
agentCommands: AgentCommandsSchema,
|
|
26896
26972
|
secrets: SecretsSchema,
|
|
26897
26973
|
personalization: toggle("Copy your desktop look (theme, accent, taskbar, wallpaper, ...) into the sandbox."),
|
|
@@ -26924,6 +27000,8 @@ var LocalOverridesSchema = external_exports.strictObject({
|
|
|
26924
27000
|
sandbox: SandboxSchema.omit({ cpuLimit: true, pageFileMb: true }).partial(),
|
|
26925
27001
|
// A project may block more (the LAN, hosts); it never opens hosts, ports, DNS or a proxy.
|
|
26926
27002
|
network: NetworkSchema.pick({ blockPrivateRanges: true, blockHosts: true }).partial(),
|
|
27003
|
+
// A project may turn the kill switch on, never off, and never choose a VPN, a server, a file or a login.
|
|
27004
|
+
vpn: VpnSchema.pick({ killSwitch: true }).partial(),
|
|
26927
27005
|
provisioning: ProvisioningSchema.pick({ copyFromHost: true, fallbackToInstall: true, refresh: true }).extend({ git: GitSchema.partial(), terminal: toggle("Windows Terminal as the sandbox window.").partial() }).partial(),
|
|
26928
27006
|
downloads: DownloadsSchema.partial(),
|
|
26929
27007
|
// Every toolchain setting, each one optional (a project usually only switches languages on or pins a version).
|
|
@@ -27064,6 +27142,16 @@ var ProjectStatusSchema = external_exports.object({
|
|
|
27064
27142
|
databases: external_exports.array(external_exports.object({ database: Text(32), port: external_exports.number().int() })).max(16),
|
|
27065
27143
|
summary: external_exports.array(Text(512)).max(64)
|
|
27066
27144
|
});
|
|
27145
|
+
var VpnStatusSchema = external_exports.object({
|
|
27146
|
+
state: external_exports.enum(["off", "starting", "up", "failed"]),
|
|
27147
|
+
message: Text(2e3),
|
|
27148
|
+
killSwitch: external_exports.boolean(),
|
|
27149
|
+
/** The server's name, e.g. uk2201.nordvpn.com. */
|
|
27150
|
+
server: Text(128).optional(),
|
|
27151
|
+
/** What the sandbox's traffic looks like from outside, once the tunnel is up. */
|
|
27152
|
+
publicIp: Text(64).optional(),
|
|
27153
|
+
updatedAt: TimeSchema
|
|
27154
|
+
});
|
|
27067
27155
|
|
|
27068
27156
|
// src/shared/io/json.ts
|
|
27069
27157
|
import fs2 from "node:fs";
|
|
@@ -27100,20 +27188,25 @@ var scan = (schema, dir) => {
|
|
|
27100
27188
|
var RunDir = class {
|
|
27101
27189
|
root;
|
|
27102
27190
|
sandboxFile;
|
|
27191
|
+
vpnFile;
|
|
27103
27192
|
requestsDir;
|
|
27104
27193
|
responsesDir;
|
|
27105
27194
|
sessionsDir;
|
|
27106
27195
|
projectsDir;
|
|
27107
27196
|
/** audit.processes: programs the sandbox started, in small .jsonl files the host takes in and deletes. */
|
|
27108
27197
|
auditDir;
|
|
27198
|
+
/** One-shot secrets the host hands over (see secrets.ts). Next to run, not in it: shared-use users can change run. */
|
|
27199
|
+
secretsDir;
|
|
27109
27200
|
constructor(dataDir2) {
|
|
27110
27201
|
this.root = path3.join(dataDir2, "run");
|
|
27111
27202
|
this.sandboxFile = path3.join(this.root, "sandbox.json");
|
|
27203
|
+
this.vpnFile = path3.join(this.root, "vpn.json");
|
|
27112
27204
|
this.requestsDir = path3.join(this.root, "requests");
|
|
27113
27205
|
this.responsesDir = path3.join(this.root, "responses");
|
|
27114
27206
|
this.sessionsDir = path3.join(this.root, "sessions");
|
|
27115
27207
|
this.projectsDir = path3.join(this.root, "projects");
|
|
27116
27208
|
this.auditDir = path3.join(this.root, "audit");
|
|
27209
|
+
this.secretsDir = path3.join(dataDir2, "secrets");
|
|
27117
27210
|
}
|
|
27118
27211
|
requestFile(id) {
|
|
27119
27212
|
return path3.join(this.requestsDir, safeId(id) + ".json");
|
|
@@ -27127,9 +27220,15 @@ var RunDir = class {
|
|
|
27127
27220
|
projectFile(name) {
|
|
27128
27221
|
return path3.join(this.projectsDir, safeId(name) + ".json");
|
|
27129
27222
|
}
|
|
27223
|
+
secretFile(id) {
|
|
27224
|
+
return path3.join(this.secretsDir, safeId(id) + ".json");
|
|
27225
|
+
}
|
|
27130
27226
|
readSandboxStatus() {
|
|
27131
27227
|
return readValid(SandboxStatusSchema, this.sandboxFile);
|
|
27132
27228
|
}
|
|
27229
|
+
readVpnStatus() {
|
|
27230
|
+
return readValid(VpnStatusSchema, this.vpnFile);
|
|
27231
|
+
}
|
|
27133
27232
|
readSession(id) {
|
|
27134
27233
|
return readValid(SessionStatusSchema, this.sessionFile(id));
|
|
27135
27234
|
}
|
|
@@ -32,6 +32,46 @@ export const accountsSuite = {
|
|
|
32
32
|
stateAfter.other === 1 &&
|
|
33
33
|
new AccountStore(storage).activeFor(dataA) === 'work', 'switching swaps in the other credentials and account, keeps the rest of the sandbox state, and marks it active');
|
|
34
34
|
t.includes(JSON.stringify(new AccountStore(storage).read('personal')?.credentials), 'personal-2', "the outgoing account's refreshed tokens are saved back before switching");
|
|
35
|
+
t.section('sharing plugins between data sets');
|
|
36
|
+
const plugA = path.join(storage, 'data', 'p1', 'state', 'claude');
|
|
37
|
+
const plugB = path.join(storage, 'data', 'p2', 'state', 'claude');
|
|
38
|
+
const plugC = path.join(storage, 'data', 'p3', 'state', 'claude');
|
|
39
|
+
const login = '{"claudeAiOauth":{"refreshToken":"x"}}';
|
|
40
|
+
for (const dir of [plugA, plugB, plugC])
|
|
41
|
+
t.write(path.join(dir, '.credentials.json'), login);
|
|
42
|
+
t.write(path.join(plugA, 'plugins', 'installed_plugins.json'), '{"version":2,"plugins":{}}');
|
|
43
|
+
t.write(path.join(plugA, 'plugins', 'cache', 'm', 'p', 'a.js'), 'x');
|
|
44
|
+
t.write(path.join(plugA, 'settings.json'), '{"theme":"dark","enabledPlugins":{"p@m":true}}');
|
|
45
|
+
t.write(path.join(plugB, 'settings.json'), '{"theme":"light","enabledPlugins":{"q@m":false}}');
|
|
46
|
+
const dataP = (n) => path.join(storage, 'data', n);
|
|
47
|
+
const off = new AccountStore(storage);
|
|
48
|
+
off.save(dataP('p1'), 'one', null);
|
|
49
|
+
off.activate(dataP('p2'), 'one');
|
|
50
|
+
t.check(!fs.existsSync(path.join(plugB, 'plugins')), 'plugins are not copied when the setting is off (default)');
|
|
51
|
+
const on = new AccountStore(storage, true);
|
|
52
|
+
on.activate(dataP('p1'), 'one');
|
|
53
|
+
on.activate(dataP('p2'), 'one');
|
|
54
|
+
const settingsB = f.readJson(path.join(plugB, 'settings.json'));
|
|
55
|
+
t.check(fs.existsSync(path.join(plugB, 'plugins', 'cache', 'm', 'p', 'a.js')) &&
|
|
56
|
+
settingsB.theme === 'light' &&
|
|
57
|
+
settingsB.enabledPlugins['p@m'] === true &&
|
|
58
|
+
settingsB.enabledPlugins['q@m'] === false &&
|
|
59
|
+
!fs.existsSync(path.join(storage, 'accounts', 'shared-plugins', '.credentials.json')), 'on: plugins and enabledPlugins reach the other data set; its own settings win and no login travels');
|
|
60
|
+
t.write(path.join(plugC, 'plugins', 'installed_plugins.json'), '{}');
|
|
61
|
+
const outside = t.dir('plugin-victim');
|
|
62
|
+
t.write(path.join(outside, 'secret.txt'), 's');
|
|
63
|
+
fs.symlinkSync(outside, path.join(plugC, 'plugins', 'cache'), 'junction');
|
|
64
|
+
on.activate(dataP('p3'), 'one');
|
|
65
|
+
t.check((on.pluginNote ?? '').includes('link') &&
|
|
66
|
+
!fs.existsSync(path.join(storage, 'accounts', 'shared-plugins', 'plugins', 'cache', 'secret.txt')), 'a link in the plugins is refused (the switch still works) and nothing behind it is copied');
|
|
67
|
+
const dataQ = dataP('p4');
|
|
68
|
+
const plugQ = path.join(dataQ, 'state', 'claude');
|
|
69
|
+
t.write(path.join(plugQ, 'plugins', 'installed_plugins.json'), '{"version":2}');
|
|
70
|
+
t.write(path.join(plugQ, 'plugins', 'cache', 'new.js'), 'n');
|
|
71
|
+
on.syncPlugins(dataQ);
|
|
72
|
+
const plugR = path.join(storage, 'data', 'p5', 'state', 'claude');
|
|
73
|
+
on.syncPlugins(dataP('p5'));
|
|
74
|
+
t.check(fs.existsSync(path.join(plugR, 'plugins', 'cache', 'new.js')), 'launch-time refresh: plugins installed in one data set reach the shared set and the next empty data set');
|
|
35
75
|
t.section('removing and refusing');
|
|
36
76
|
new AccountStore(storage).setDefault('work');
|
|
37
77
|
new AccountStore(storage).remove('work');
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
// Agent commands in every terminal, SQLite folders of agents, and the PATH rules (planner, rebuild, shell start-up).
|
|
2
|
+
import { spawnSync } from 'node:child_process';
|
|
3
|
+
import fs from 'node:fs';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import { DEFAULTS, mergeConfig, validateConfig } from '../core/config/index.js';
|
|
6
|
+
import { isWin } from '../core/util/index.js';
|
|
7
|
+
import { SYSTEM } from '../shared/system.js';
|
|
8
|
+
import { agentCommand, agentShims, isCopyableDatabaseFile, isDatabaseFile, localStateEntries, shimText, } from '../guest/agents/agent-files.js';
|
|
9
|
+
import { appendMissing, expandVars, isPinnedNodeDir, parseRegPath, pathKey, planPath, rebuildPath, splitPath, } from '../guest/setup/path-plan.js';
|
|
10
|
+
import { withReloadEnvironment } from '../host/tools/index.js';
|
|
11
|
+
import { HarnessSchema } from '../core/schema/index.js';
|
|
12
|
+
export const agentPathsSuite = {
|
|
13
|
+
name: 'agent-paths',
|
|
14
|
+
title: 'agent commands, agent SQLite folders and PATH rules',
|
|
15
|
+
run: (t) => {
|
|
16
|
+
t.section('agent commands');
|
|
17
|
+
const tools = 'C:\\AgentData\\tools';
|
|
18
|
+
const shims = agentShims(tools, DEFAULTS.harnesses);
|
|
19
|
+
const codex = shims.find((s) => s.name === 'codex');
|
|
20
|
+
t.equal(codex?.command, 'codex', 'codex is typed as codex');
|
|
21
|
+
t.equal(codex?.target, tools + '\\agents\\codex\\codex.cmd', 'an npm agent runs its .cmd');
|
|
22
|
+
t.equal(shims.find((s) => s.name === 'claude')?.target, tools + '\\agents\\claude\\claude.exe', 'claude runs its .exe');
|
|
23
|
+
t.check(shims.length === Object.keys(DEFAULTS.harnesses).length, 'every built-in agent gets a command');
|
|
24
|
+
t.equal(agentCommand('aider', DEFAULTS.harnesses.aider), 'aider', 'a uv agent is typed as its uv command');
|
|
25
|
+
const text = shimText(codex, { node: 'C:\\n\\node.exe', script: 'C:\\r\\agent.js' });
|
|
26
|
+
t.check(text.includes('\r\n') && text.includes('install codex') && text.endsWith('%*\r\n'), 'the command installs on first use');
|
|
27
|
+
t.check(text.includes('if exist "%SBX_REAL%" goto run'), 'an installed agent starts at once');
|
|
28
|
+
t.equal(agentShims(tools, { 'bad name': DEFAULTS.harnesses.codex }).length, 0, 'an agent name that is not a plain word gets no command file');
|
|
29
|
+
t.section('agent SQLite folders');
|
|
30
|
+
t.equal(DEFAULTS.harnesses.codex.localState, { CODEX_SQLITE_HOME: 'sqlite' }, 'codex runs its databases locally');
|
|
31
|
+
const entries = localStateEntries(DEFAULTS.harnesses, 'C:\\AgentData\\state', 'C:\\nvm\\agent-state');
|
|
32
|
+
t.equal(entries.map((e) => [e.agent, e.env, e.store, e.local, e.processes[0]]), [
|
|
33
|
+
[
|
|
34
|
+
'codex',
|
|
35
|
+
'CODEX_SQLITE_HOME',
|
|
36
|
+
'C:\\AgentData\\state\\codex\\sqlite',
|
|
37
|
+
'C:\\nvm\\agent-state\\codex\\sqlite',
|
|
38
|
+
'codex.exe',
|
|
39
|
+
],
|
|
40
|
+
], 'saved copy in the state folder, working copy on the sandbox disk');
|
|
41
|
+
// A user's own harnesses.codex is merged over the built-in one: fields it leaves out (localState) stay.
|
|
42
|
+
const { localState: _omitted, ...pinned } = DEFAULTS.harnesses.codex;
|
|
43
|
+
const merged = (harnesses) => validateConfig(mergeConfig(DEFAULTS, { harnesses }), 'test').harnesses;
|
|
44
|
+
t.equal([
|
|
45
|
+
merged({ codex: { npmPackage: '@openai/codex@0.9.0' } }).codex.localState,
|
|
46
|
+
merged({ codex: pinned }).codex.localState,
|
|
47
|
+
], [{ CODEX_SQLITE_HOME: 'sqlite' }, { CODEX_SQLITE_HOME: 'sqlite' }], 'a customized or pinned built-in agent keeps localState from the defaults');
|
|
48
|
+
t.check(HarnessSchema.safeParse({ ...DEFAULTS.harnesses.codex, localState: { X: '..\\up' } }).success === false, 'a local state folder cannot leave the agent state folder');
|
|
49
|
+
t.equal(['state_5.sqlite', 'x.sqlite-wal', 'x.sqlite-shm', 'a.db', 'auth.json'].map(isDatabaseFile), [true, true, true, true, false], 'database files are told apart');
|
|
50
|
+
t.equal(['state_5.sqlite', 'x.sqlite-wal', 'x.sqlite-shm'].map(isCopyableDatabaseFile), [true, true, false], 'the -shm file is not copied (SQLite rebuilds it)');
|
|
51
|
+
t.section('PATH planner');
|
|
52
|
+
const present = new Set(['c:\\a', 'c:\\b', 'c:\\c\\d', 'c:\\nvm\\v24.1.0']);
|
|
53
|
+
const exists = (f) => present.has(pathKey(f));
|
|
54
|
+
t.equal(planPath({ entries: ['C:\\A\\;c:\\b', 'C:\\a', 'C:\\missing;"C:\\C\\D"', '', 'c:/B'], exists }), ['C:\\A\\', 'c:\\b', 'C:\\C\\D'], 'ordered, no duplicates (case, slash, quotes), no missing folders');
|
|
55
|
+
t.equal(planPath({ entries: ['C:\\a;C:\\nvm\\v24.1.0'], exists, drop: (f) => isPinnedNodeDir(f, 'C:\\NVM') }), ['C:\\a'], 'a pinned node version is never machine-wide');
|
|
56
|
+
t.check(isPinnedNodeDir('C:\\nvm\\v24.1.0\\', 'C:\\nvm') && !isPinnedNodeDir('C:\\nvm', 'C:\\nvm'), 'only versions are pinned');
|
|
57
|
+
t.equal(pathKey('C:\\'), 'c:\\', 'a drive root keeps its slash');
|
|
58
|
+
t.equal(splitPath(' "C:\\a" ;; C:\\b;'), ['C:\\a', 'C:\\b'], 'splitting drops empty parts and quotes');
|
|
59
|
+
t.equal(expandVars('%SystemRoot%\\x;%nope%', { SYSTEMROOT: 'C:\\W' }), 'C:\\W\\x;%nope%', 'variables expand in any case');
|
|
60
|
+
t.equal(appendMissing('C:\\a;C:\\b', 'c:\\B;C:\\n;C:\\skip', (f) => f === 'C:\\skip'), 'C:\\a;C:\\b;C:\\n', 'missing folders go last');
|
|
61
|
+
t.equal(rebuildPath({
|
|
62
|
+
machine: 'C:\\a\\;%SystemRoot%;C:\\b',
|
|
63
|
+
user: 'c:\\B;C:\\u',
|
|
64
|
+
process: 'C:\\only;C:\\A;C:\\AgentData\\tools\\node',
|
|
65
|
+
env: { SystemRoot: 'C:\\Windows' },
|
|
66
|
+
skip: (f) => pathKey(f) === 'c:\\agentdata\\tools\\node',
|
|
67
|
+
}), 'C:\\only;C:\\a\\;C:\\Windows;C:\\b;C:\\u', 'a new shell: process-only entries first, then the registry, no duplicates, no runner node');
|
|
68
|
+
t.equal(parseRegPath('\r\nHKEY_LOCAL_MACHINE\\X\r\n Path REG_EXPAND_SZ C:\\a;%SystemRoot%\r\n\r\n'), 'C:\\a;%SystemRoot%', 'reg query output is parsed');
|
|
69
|
+
t.equal(parseRegPath('ERROR: nothing'), '', 'no Path value is an empty PATH');
|
|
70
|
+
t.section('Windows Terminal reloads the environment');
|
|
71
|
+
t.equal(withReloadEnvironment({ compatibility: { reloadEnvironmentVariables: true } }), null, 'already set: unchanged');
|
|
72
|
+
t.equal(withReloadEnvironment({ theme: 'dark', compatibility: { other: 1 } })?.compatibility, { other: 1, reloadEnvironmentVariables: true }, 'set without touching the rest of compatibility');
|
|
73
|
+
if (!isWin)
|
|
74
|
+
return;
|
|
75
|
+
t.section('shell start-up (pathsync.exe and the start-up files)');
|
|
76
|
+
const dir = t.at('pathsync');
|
|
77
|
+
const exe = path.join(dir, 'pathsync.exe');
|
|
78
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
79
|
+
const csc = spawnSync(SYSTEM.csc(), ['/nologo', '/out:' + exe, path.join(t.packageRoot, 'sandbox', 'csharp', 'PathSync.cs')], { encoding: 'utf8', windowsHide: true });
|
|
80
|
+
t.check(csc.status === 0, 'PathSync.cs compiles', csc.stdout);
|
|
81
|
+
if (csc.status !== 0)
|
|
82
|
+
return;
|
|
83
|
+
const sync = spawnSync(exe, [
|
|
84
|
+
'--machine',
|
|
85
|
+
'C:\\a\\;%SystemRoot%;C:\\b',
|
|
86
|
+
'--user',
|
|
87
|
+
'c:\\B;C:\\u',
|
|
88
|
+
'--process',
|
|
89
|
+
'C:\\only;C:\\A;C:\\AgentData\\tools\\node',
|
|
90
|
+
], { encoding: 'utf8', windowsHide: true, env: { ...process.env, AGENT_TOOLS: 'C:\\AgentData\\tools' } });
|
|
91
|
+
t.equal(sync.stdout, 'C:\\only;C:\\a\\;' + (process.env.SystemRoot ?? 'C:\\Windows') + ';C:\\b;C:\\u', 'pathsync.exe follows the same rules');
|
|
92
|
+
const root = t.at('shell-root');
|
|
93
|
+
const install = spawnSync(SYSTEM.powershell(), [
|
|
94
|
+
'-NoLogo',
|
|
95
|
+
'-NoProfile',
|
|
96
|
+
'-ExecutionPolicy',
|
|
97
|
+
'Bypass',
|
|
98
|
+
'-File',
|
|
99
|
+
path.join(t.packageRoot, 'sandbox', 'scripts', 'install-shell-path.ps1'),
|
|
100
|
+
'-Helper',
|
|
101
|
+
exe,
|
|
102
|
+
'-Root',
|
|
103
|
+
root,
|
|
104
|
+
], { encoding: 'utf8', windowsHide: true });
|
|
105
|
+
t.check(install.status === 0, 'install-shell-path.ps1 runs (to a temp folder, no registry)', install.stderr);
|
|
106
|
+
const cmdFile = path.join(dir, 'shell-path.cmd');
|
|
107
|
+
// Quotes and & in the command line of cmd /c must not run the script again (that once looped for ever).
|
|
108
|
+
const nested = spawnSync(SYSTEM.cmd(), ['/d', '/c', 'echo "a & b" & call "' + cmdFile + '" && echo guard-ok'], {
|
|
109
|
+
encoding: 'utf8',
|
|
110
|
+
windowsHide: true,
|
|
111
|
+
windowsVerbatimArguments: true,
|
|
112
|
+
});
|
|
113
|
+
t.check(nested.stdout.includes('guard-ok') && !nested.stdout.includes('RECURSION'), 'the cmd start-up file leaves `cmd /c` alone');
|
|
114
|
+
},
|
|
115
|
+
};
|
|
@@ -4,10 +4,15 @@ import { safeId } from '../shared/channel/index.js';
|
|
|
4
4
|
import { GuestRequestSchema, SandboxStatusSchema, SessionStatusSchema } from '../shared/channel/index.js';
|
|
5
5
|
import { bootLine, firstStartNotice, pendingDownloads, readyIn, stillWorking } from '../cli/commands/launch/index.js';
|
|
6
6
|
import { encodeFrame, FrameReader, FrameType, fixWindowsKeys, helloFrame, InputJoiner, MAX_FRAME_BYTES, MOUSE_OFF, OutputFilter, } from '../shared/pty/index.js';
|
|
7
|
+
import { bootSilent, FIRST_STATUS_MS } from '../host/channel/index.js';
|
|
7
8
|
export const channelSuite = {
|
|
8
9
|
name: 'channel',
|
|
9
10
|
title: 'request/status validation and the terminal protocol (frames, OSC 52, keys)',
|
|
10
11
|
run: async (t) => {
|
|
12
|
+
t.section('a silent boot');
|
|
13
|
+
t.check(!bootSilent(FIRST_STATUS_MS - 1, false) &&
|
|
14
|
+
bootSilent(FIRST_STATUS_MS + 1, false) &&
|
|
15
|
+
!bootSilent(10 * FIRST_STATUS_MS, true), 'a boot is silent only when no status came within the first three minutes');
|
|
11
16
|
t.section('requests and session status');
|
|
12
17
|
const validRequest = (r) => GuestRequestSchema.safeParse(r).success;
|
|
13
18
|
const validSession = (s) => SessionStatusSchema.safeParse(s).success;
|