windows-development-sandbox 1.7.0 → 1.9.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/config.example.json +10 -0
- package/dist/app/context.d.ts +8 -0
- package/dist/app/context.js +12 -0
- package/dist/app/features/defs.d.ts +322 -0
- package/dist/app/features/defs.js +28 -0
- package/dist/app/features/sandbox/index.d.ts +2 -0
- package/dist/app/features/sandbox/index.js +3 -0
- package/dist/app/features/sandbox/sandbox.def.d.ts +193 -0
- package/dist/app/features/sandbox/sandbox.def.js +245 -0
- package/dist/app/features/sandbox/sandbox.run.d.ts +72 -0
- package/dist/app/features/sandbox/sandbox.run.js +98 -0
- package/dist/app/features/sessions/index.d.ts +2 -0
- package/dist/app/features/sessions/index.js +3 -0
- package/dist/app/features/sessions/sessions.def.d.ts +141 -0
- package/dist/app/features/sessions/sessions.def.js +176 -0
- package/dist/app/features/sessions/sessions.run.d.ts +39 -0
- package/dist/app/features/sessions/sessions.run.js +58 -0
- package/dist/{cli/menu/settings/categories.d.ts → app/features/settings/categories.def.d.ts} +2 -0
- package/dist/{cli/menu/settings/categories.js → app/features/settings/categories.def.js} +24 -5
- package/dist/app/features/settings/index.d.ts +5 -0
- package/dist/app/features/settings/index.js +6 -0
- package/dist/{cli/menu/settings/config-file.d.ts → app/features/settings/settings-file.d.ts} +1 -1
- package/dist/{cli/menu/settings/config-file.js → app/features/settings/settings-file.js} +1 -1
- package/dist/app/features/settings/settings-rows.d.ts +35 -0
- package/dist/app/features/settings/settings-rows.js +94 -0
- package/dist/app/features/settings/settings.def.d.ts +157 -0
- package/dist/app/features/settings/settings.def.js +179 -0
- package/dist/app/features/settings/settings.run.d.ts +67 -0
- package/dist/app/features/settings/settings.run.js +84 -0
- package/dist/app/kernel/define.d.ts +143 -0
- package/dist/app/kernel/define.js +42 -0
- package/dist/app/kernel/errors.d.ts +34 -0
- package/dist/app/kernel/errors.js +45 -0
- package/dist/app/kernel/fields.d.ts +70 -0
- package/dist/app/kernel/fields.js +243 -0
- package/dist/app/kernel/index.d.ts +8 -0
- package/dist/app/kernel/index.js +10 -0
- package/dist/app/kernel/io.d.ts +193 -0
- package/dist/app/kernel/io.js +126 -0
- package/dist/app/kernel/rpc.d.ts +156 -0
- package/dist/app/kernel/rpc.js +47 -0
- package/dist/app/kernel/text.d.ts +6 -0
- package/dist/app/kernel/text.js +57 -0
- package/dist/app/kernel/view.d.ts +146 -0
- package/dist/app/kernel/view.js +28 -0
- package/dist/app/registry.d.ts +10 -0
- package/dist/app/registry.js +50 -0
- package/dist/cli/args.d.ts +5 -0
- package/dist/cli/args.js +6 -0
- package/dist/cli/commands/engine.d.ts +2 -0
- package/dist/cli/commands/engine.js +60 -0
- package/dist/cli/commands/index.d.ts +1 -1
- package/dist/cli/commands/index.js +1 -1
- package/dist/cli/commands/launch/launch.js +47 -7
- package/dist/cli/commands/launch/prepare.js +3 -3
- package/dist/cli/commands/launch/running.js +2 -1
- package/dist/cli/commands/launch/summary.d.ts +2 -0
- package/dist/cli/commands/maintenance/config-share.d.ts +12 -0
- package/dist/cli/commands/maintenance/config-share.js +80 -0
- package/dist/cli/commands/maintenance/config.js +8 -82
- package/dist/cli/commands/maintenance/logs.js +14 -0
- package/dist/cli/commands/registry.js +3 -7
- package/dist/cli/commands/repair/checks/contained.d.ts +2 -0
- package/dist/cli/commands/repair/checks/contained.js +139 -0
- package/dist/cli/commands/repair/checks/hcs.d.ts +7 -0
- package/dist/cli/commands/repair/checks/hcs.js +28 -0
- package/dist/cli/commands/repair/checks/index.js +4 -0
- package/dist/cli/commands/repair/checks/pc.js +32 -1
- package/dist/cli/commands/repair/checks/sandbox.js +16 -1
- package/dist/cli/commands/repair/checks/vpn.js +34 -9
- package/dist/cli/commands/repair/env.js +2 -1
- package/dist/cli/commands/sessions/index.d.ts +0 -4
- package/dist/cli/commands/sessions/index.js +3 -7
- package/dist/cli/commands/shared-use.d.ts +5 -2
- package/dist/cli/commands/shared-use.js +11 -8
- package/dist/cli/commands/storage/contained.d.ts +3 -0
- package/dist/cli/commands/storage/contained.js +179 -0
- package/dist/cli/commands/storage/offer.js +7 -1
- package/dist/cli/commands/storage/storage.js +10 -2
- package/dist/cli/commands/user-config.js +1 -1
- package/dist/cli/commands/vpn.js +19 -3
- package/dist/cli/commands/web.js +2 -0
- package/dist/cli/index.js +2 -1
- package/dist/cli/manifest.d.ts +72 -104
- package/dist/cli/manifest.js +64 -39
- package/dist/cli/menu/add-agent.d.ts +1 -1
- package/dist/cli/menu/add-agent.js +1 -1
- package/dist/cli/menu/apps.d.ts +7 -1
- package/dist/cli/menu/apps.js +36 -0
- package/dist/cli/menu/command-fields.d.ts +1 -1
- package/dist/cli/menu/command-form.js +2 -2
- package/dist/cli/menu/io-menu.d.ts +29 -0
- package/dist/cli/menu/io-menu.js +126 -0
- package/dist/cli/menu/live.d.ts +27 -0
- package/dist/cli/menu/live.js +69 -0
- package/dist/cli/menu/memory.d.ts +19 -0
- package/dist/cli/menu/memory.js +53 -0
- package/dist/cli/menu/menu.d.ts +10 -1
- package/dist/cli/menu/menu.js +27 -9
- package/dist/cli/menu/pages/agents-page.d.ts +3 -1
- package/dist/cli/menu/pages/agents-page.js +12 -5
- package/dist/cli/menu/pages/apps-page.d.ts +3 -1
- package/dist/cli/menu/pages/apps-page.js +19 -2
- package/dist/cli/menu/pages/list-page.d.ts +27 -0
- package/dist/cli/menu/pages/list-page.js +109 -7
- package/dist/cli/menu/pages/maintenance-page.d.ts +0 -5
- package/dist/cli/menu/pages/maintenance-page.js +17 -19
- package/dist/cli/menu/pages/sandbox-page.d.ts +4 -6
- package/dist/cli/menu/pages/sandbox-page.js +26 -118
- package/dist/cli/menu/pages/scopes.d.ts +1 -1
- package/dist/cli/menu/pages/sessions-page.d.ts +5 -11
- package/dist/cli/menu/pages/sessions-page.js +19 -88
- package/dist/cli/menu/pages/settings-page.d.ts +2 -10
- package/dist/cli/menu/pages/settings-page.js +64 -94
- package/dist/cli/menu/render-view.d.ts +28 -0
- package/dist/cli/menu/render-view.js +112 -0
- package/dist/cli/menu/settings/{path-kind.d.ts → ask-path.d.ts} +1 -7
- package/dist/cli/menu/settings/ask-path.js +14 -0
- package/dist/cli/menu/settings/collections/collection-editor.d.ts +1 -1
- package/dist/cli/menu/settings/collections/string-list-editor.d.ts +1 -2
- package/dist/cli/menu/settings/collections/string-list-editor.js +1 -1
- package/dist/cli/menu/settings/draft.d.ts +1 -1
- package/dist/cli/menu/settings/format.d.ts +1 -3
- package/dist/cli/menu/settings/format.js +6 -36
- package/dist/cli/menu/settings/index.d.ts +1 -3
- package/dist/cli/menu/settings/index.js +3 -3
- package/dist/cli/menu/settings/object-editor.d.ts +1 -1
- package/dist/cli/menu/settings/share.d.ts +36 -0
- package/dist/cli/menu/settings/share.js +131 -0
- package/dist/cli/menu/settings/value-editor.d.ts +5 -1
- package/dist/cli/menu/settings/value-editor.js +57 -54
- package/dist/cli/menu/several.js +1 -1
- package/dist/cli/menu/share-settings.d.ts +21 -0
- package/dist/cli/menu/share-settings.js +112 -0
- package/dist/cli/menu/shell.d.ts +21 -5
- package/dist/cli/menu/shell.js +31 -6
- package/dist/cli/menu/views.d.ts +7 -0
- package/dist/cli/menu/views.js +11 -0
- package/dist/cli/menu/vpn-login.js +8 -0
- package/dist/cli/operations/handler.d.ts +6 -0
- package/dist/cli/operations/handler.js +61 -0
- package/dist/cli/operations/index.d.ts +4 -0
- package/dist/cli/operations/index.js +5 -0
- package/dist/cli/operations/input.d.ts +6 -0
- package/dist/cli/operations/input.js +37 -0
- package/dist/cli/operations/io-cli.d.ts +7 -0
- package/dist/cli/operations/io-cli.js +62 -0
- package/dist/cli/operations/spec.d.ts +18 -0
- package/dist/cli/operations/spec.js +108 -0
- package/dist/cli/output/colors.d.ts +2 -2
- package/dist/cli/output/colors.js +2 -11
- package/dist/cli/output/index.d.ts +1 -0
- package/dist/cli/output/index.js +1 -0
- package/dist/cli/output/print.d.ts +3 -1
- package/dist/cli/output/print.js +7 -3
- package/dist/cli/output/progress.d.ts +15 -0
- package/dist/cli/output/progress.js +44 -0
- package/dist/cli/output/render-view.d.ts +4 -0
- package/dist/cli/output/render-view.js +63 -0
- package/dist/cli/services/agent-commands-service.d.ts +2 -0
- package/dist/cli/services/agent-commands-service.js +11 -2
- package/dist/cli/services/logs-service.js +4 -3
- package/dist/cli/tui/app.d.ts +6 -1
- package/dist/cli/tui/app.js +26 -4
- package/dist/cli/tui/list/list-screen.d.ts +14 -0
- package/dist/cli/tui/list/list-screen.js +64 -36
- package/dist/cli/tui/list/list-types.d.ts +2 -0
- package/dist/cli/tui/terminal.d.ts +7 -0
- package/dist/cli/tui/terminal.js +30 -10
- package/dist/core/config/defaults.js +8 -0
- package/dist/core/schema/config.d.ts +13 -0
- package/dist/core/schema/config.js +16 -1
- package/dist/core/schema/harness.d.ts +1 -0
- package/dist/core/schema/harness.js +5 -0
- package/dist/core/schema/sandbox.d.ts +6 -0
- package/dist/core/schema/sandbox.js +20 -3
- package/dist/core/schema/vpn.d.ts +2 -1
- package/dist/core/schema/vpn.js +3 -3
- package/dist/core/types.d.ts +23 -5
- package/dist/core/util/fs.d.ts +2 -0
- package/dist/core/util/fs.js +9 -0
- package/dist/core/util/index.d.ts +1 -1
- package/dist/core/util/index.js +1 -1
- package/dist/guest/agents/agent-files.d.ts +5 -0
- package/dist/guest/agents/agent-files.js +4 -0
- package/dist/guest/agents/local-state.d.ts +2 -0
- package/dist/guest/agents/local-state.js +21 -1
- package/dist/guest/boot/boot.js +2 -1
- package/dist/guest/daemon/daemon.js +4 -0
- package/dist/guest/daemon/sessions.d.ts +5 -0
- package/dist/guest/daemon/sessions.js +17 -3
- package/dist/guest/entries/daemon.js +3 -0
- package/dist/guest/governor/decide.d.ts +61 -0
- package/dist/guest/governor/decide.js +182 -0
- package/dist/guest/governor/governor.d.ts +42 -0
- package/dist/guest/governor/governor.js +214 -0
- package/dist/guest/governor/index.d.ts +2 -0
- package/dist/guest/governor/index.js +2 -0
- package/dist/guest/runtime/csc.d.ts +1 -0
- package/dist/guest/runtime/csc.js +1 -0
- package/dist/guest/sessions/viewer.js +3 -1
- package/dist/guest/toolchains/native/rust-extras.js +4 -2
- package/dist/guest/vpn/vpn.js +69 -21
- package/dist/guest/vpn/wireguard.d.ts +32 -0
- package/dist/guest/vpn/wireguard.js +132 -0
- package/dist/host/agent-commands/commands.d.ts +4 -0
- package/dist/host/agent-commands/commands.js +31 -7
- package/dist/host/audit/log.d.ts +1 -1
- package/dist/host/channel/attach.d.ts +3 -1
- package/dist/host/channel/attach.js +5 -2
- package/dist/host/channel/channel.d.ts +2 -0
- package/dist/host/channel/channel.js +4 -0
- package/dist/host/engines/engine.d.ts +12 -0
- package/dist/host/engines/engine.js +1 -0
- package/dist/host/engines/hcs/check.d.ts +25 -0
- package/dist/host/engines/hcs/check.js +95 -0
- package/dist/host/engines/hcs/documents.d.ts +44 -0
- package/dist/host/engines/hcs/documents.js +155 -0
- package/dist/host/engines/hcs/engine.d.ts +39 -0
- package/dist/host/engines/hcs/engine.js +171 -0
- package/dist/host/engines/hcs/helper.d.ts +43 -0
- package/dist/host/engines/hcs/helper.js +173 -0
- package/dist/host/engines/hcs/images.d.ts +37 -0
- package/dist/host/engines/hcs/images.js +152 -0
- package/dist/host/engines/index.d.ts +7 -0
- package/dist/host/engines/index.js +5 -0
- package/dist/host/engines/registry.d.ts +16 -0
- package/dist/host/engines/registry.js +30 -0
- package/dist/host/engines/types.d.ts +58 -0
- package/dist/host/engines/types.js +1 -0
- package/dist/host/engines/windows-sandbox/engine.d.ts +16 -0
- package/dist/host/engines/windows-sandbox/engine.js +63 -0
- package/dist/host/engines/windows-sandbox/wsb-text.d.ts +2 -0
- package/dist/host/engines/windows-sandbox/wsb-text.js +29 -0
- package/dist/host/launch/generate.d.ts +5 -1
- package/dist/host/launch/generate.js +50 -8
- package/dist/host/launch/index.d.ts +3 -1
- package/dist/host/launch/index.js +3 -1
- package/dist/host/launch/launch-plan.d.ts +13 -0
- package/dist/host/launch/launch-plan.js +26 -0
- package/dist/host/launch/mappings.js +2 -1
- package/dist/host/launch/risk-notes.d.ts +10 -0
- package/dist/host/launch/risk-notes.js +18 -0
- package/dist/host/launch/session-file.d.ts +2 -0
- package/dist/host/launch/session-file.js +7 -1
- package/dist/host/launch/wsb-file.d.ts +28 -4
- package/dist/host/launch/wsb-file.js +61 -42
- package/dist/host/life/crash-report.d.ts +27 -1
- package/dist/host/life/crash-report.js +173 -7
- package/dist/host/life/host-memory.d.ts +40 -0
- package/dist/host/life/host-memory.js +137 -0
- package/dist/host/life/index.d.ts +2 -0
- package/dist/host/life/index.js +2 -0
- package/dist/host/life/stop-events.d.ts +2 -0
- package/dist/host/life/stop-events.js +20 -3
- package/dist/host/life/stop-warning.js +1 -1
- package/dist/host/life/watchdog.d.ts +54 -0
- package/dist/host/life/watchdog.js +108 -0
- package/dist/host/native.d.ts +3 -2
- package/dist/host/native.js +22 -3
- package/dist/host/profile/claude-login.js +3 -2
- package/dist/host/sandbox/contained-deps.d.ts +2 -0
- package/dist/host/sandbox/contained-deps.js +17 -0
- package/dist/host/sandbox/index.d.ts +2 -0
- package/dist/host/sandbox/index.js +2 -0
- package/dist/host/sandbox/platform.d.ts +2 -0
- package/dist/host/sandbox/platform.js +7 -7
- package/dist/host/sandbox/tasklist.d.ts +13 -0
- package/dist/host/sandbox/tasklist.js +47 -0
- package/dist/host/secrets/launch-secrets.js +2 -1
- package/dist/host/sharing/current.js +2 -6
- package/dist/host/storage/contained/check.d.ts +9 -0
- package/dist/host/storage/contained/check.js +37 -0
- package/dist/host/storage/contained/contained-storage.d.ts +66 -0
- package/dist/host/storage/contained/contained-storage.js +168 -0
- package/dist/host/storage/contained/disk-port.d.ts +43 -0
- package/dist/host/storage/contained/disk-port.js +122 -0
- package/dist/host/storage/contained/index.d.ts +9 -0
- package/dist/host/storage/contained/index.js +8 -0
- package/dist/host/storage/contained/layout.d.ts +28 -0
- package/dist/host/storage/contained/layout.js +45 -0
- package/dist/host/storage/contained/resolve.d.ts +4 -0
- package/dist/host/storage/contained/resolve.js +30 -0
- package/dist/host/storage/contained/setting.d.ts +1 -0
- package/dist/host/storage/contained/setting.js +5 -0
- package/dist/host/storage/contained/state.d.ts +89 -0
- package/dist/host/storage/contained/state.js +166 -0
- package/dist/host/storage/contained/transfer.d.ts +24 -0
- package/dist/host/storage/contained/transfer.js +121 -0
- package/dist/host/storage/index.d.ts +2 -0
- package/dist/host/storage/index.js +2 -0
- package/dist/host/storage/providers/contained.d.ts +15 -0
- package/dist/host/storage/providers/contained.js +39 -0
- package/dist/host/storage/providers/folder.d.ts +12 -0
- package/dist/host/storage/providers/folder.js +20 -0
- package/dist/host/storage/providers/index.d.ts +4 -0
- package/dist/host/storage/providers/index.js +3 -0
- package/dist/host/storage/providers/registry.d.ts +9 -0
- package/dist/host/storage/providers/registry.js +14 -0
- package/dist/host/storage/providers/types.d.ts +33 -0
- package/dist/host/storage/providers/types.js +1 -0
- package/dist/host/tools/conpty.js +3 -2
- package/dist/host/tools/windows-terminal.js +8 -7
- package/dist/host/vpn/index.d.ts +1 -1
- package/dist/host/vpn/index.js +1 -1
- package/dist/host/vpn/prepare.d.ts +2 -0
- package/dist/host/vpn/prepare.js +63 -2
- package/dist/host/web/browser.d.ts +2 -0
- package/dist/host/web/browser.js +14 -1
- package/dist/host/web/index.d.ts +3 -2
- package/dist/host/web/index.js +3 -2
- package/dist/host/web/rpc.d.ts +24 -0
- package/dist/host/web/rpc.js +149 -0
- package/dist/host/web/runner.d.ts +2 -0
- package/dist/host/web/runner.js +1 -2
- package/dist/host/web/server.d.ts +7 -0
- package/dist/host/web/server.js +23 -3
- package/dist/runtime/agent.js +69 -8
- package/dist/runtime/daemon.js +1058 -624
- package/dist/runtime/db.js +69 -8
- package/dist/runtime/main.js +624 -182
- package/dist/runtime/netproxy.js +69 -8
- package/dist/runtime/view.js +87 -13
- package/dist/selftest/agent-paths.test.js +11 -1
- package/dist/selftest/app.test.d.ts +2 -0
- package/dist/selftest/app.test.js +324 -0
- package/dist/selftest/channel.test.js +13 -0
- package/dist/selftest/cli.test.js +2 -1
- package/dist/selftest/config.test.js +59 -0
- package/dist/selftest/contained.test.d.ts +2 -0
- package/dist/selftest/contained.test.js +544 -0
- package/dist/selftest/credentials.test.js +1 -1
- package/dist/selftest/engine.test.d.ts +2 -0
- package/dist/selftest/engine.test.js +127 -0
- package/dist/selftest/hcs.test.d.ts +2 -0
- package/dist/selftest/hcs.test.js +482 -0
- package/dist/selftest/heavy-load.test.d.ts +2 -0
- package/dist/selftest/heavy-load.test.js +329 -0
- package/dist/selftest/index.js +12 -0
- package/dist/selftest/layout.test.js +12 -0
- package/dist/selftest/menu-perf.test.d.ts +2 -0
- package/dist/selftest/menu-perf.test.js +248 -0
- package/dist/selftest/menu-screens.js +4 -2
- package/dist/selftest/menu.test.js +36 -8
- package/dist/selftest/support/engine-cases.d.ts +8 -0
- package/dist/selftest/support/engine-cases.js +65 -0
- package/dist/selftest/support/engine-golden.d.ts +3 -0
- package/dist/selftest/support/engine-golden.js +66 -0
- package/dist/selftest/support/fixtures.d.ts +7 -1
- package/dist/selftest/support/hcs-probes.d.ts +17 -0
- package/dist/selftest/support/hcs-probes.js +41 -0
- package/dist/selftest/vpn.test.js +136 -3
- package/dist/selftest/web.test.js +101 -3
- package/dist/shared/channel/run-dir.d.ts +4 -1
- package/dist/shared/channel/run-dir.js +7 -1
- package/dist/shared/channel/schema.d.ts +35 -1
- package/dist/shared/channel/schema.js +27 -0
- package/dist/shared/channel/secrets.d.ts +1 -0
- package/dist/shared/channel/secrets.js +6 -0
- package/dist/shared/memory/index.d.ts +1 -0
- package/dist/shared/memory/index.js +1 -0
- package/dist/shared/memory/policy.d.ts +33 -0
- package/dist/shared/memory/policy.js +55 -0
- package/dist/shared/pty/output-filter.d.ts +14 -1
- package/dist/shared/pty/output-filter.js +22 -4
- package/dist/shared/pty/terminal.d.ts +4 -1
- package/dist/shared/pty/terminal.js +4 -2
- package/dist/shared/system.d.ts +1 -0
- package/dist/shared/system.js +1 -0
- package/dist/shared/vpn/download.d.ts +16 -0
- package/dist/shared/vpn/download.js +16 -0
- package/dist/shared/vpn/wireguard.d.ts +51 -0
- package/dist/shared/vpn/wireguard.js +227 -0
- package/dist/sync/sync-cycle.js +5 -5
- package/dist/sync/watcher.d.ts +13 -0
- package/dist/sync/watcher.js +92 -3
- package/dist/web/index.html +4 -3
- package/dist/web/main-NRRS5O6Z.js +157 -0
- package/dist/web/main-T5DMCHYV.css +1 -0
- package/native/csharp/HcsHost/AssemblyInfo.cs +14 -0
- package/native/csharp/HcsHost/Guard.cs +100 -0
- package/native/csharp/HcsHost/Hcs.cs +256 -0
- package/native/csharp/HcsHost/Json.cs +78 -0
- package/native/csharp/HcsHost/Program.cs +185 -0
- package/native/csharp/HcsHost/VirtualDisk.cs +95 -0
- package/native/csharp/HostTools/AssemblyInfo.cs +14 -0
- package/native/csharp/HostTools/MemoryStatus.cs +107 -0
- package/native/csharp/HostTools/Program.cs +58 -17
- package/native/scripts/check-contained.ps1 +28 -0
- package/native/scripts/contained-common.ps1 +241 -0
- package/native/scripts/dismount-contained.ps1 +66 -0
- package/native/scripts/memory-status.ps1 +34 -0
- package/native/scripts/mount-contained.ps1 +139 -0
- package/native/scripts/run-elevated.ps1 +17 -4
- package/native/scripts/stop-events.ps1 +23 -8
- package/package.json +9 -2
- package/sandbox/csharp/MemGov.cs +398 -0
- package/sandbox/csharp/PtyHost.cs +111 -5
- package/schemas/config.schema.json +60 -6
- package/schemas/sandbox-config.schema.json +3 -3
- package/dist/cli/commands/sessions/control.d.ts +0 -4
- package/dist/cli/commands/sessions/control.js +0 -66
- package/dist/cli/commands/sessions/list.d.ts +0 -2
- package/dist/cli/commands/sessions/list.js +0 -48
- package/dist/cli/commands/sessions/status.d.ts +0 -4
- package/dist/cli/commands/sessions/status.js +0 -114
- package/dist/cli/commands/sessions/window.d.ts +0 -3
- package/dist/cli/commands/sessions/window.js +0 -18
- package/dist/cli/menu/settings/path-kind.js +0 -44
- package/dist/web/main-CXESL347.js +0 -45
- package/dist/web/main-VLR7DVQ4.css +0 -1
- /package/dist/{cli/menu/settings → app/kernel}/schema-node.d.ts +0 -0
- /package/dist/{cli/menu/settings → app/kernel}/schema-node.js +0 -0
|
@@ -3,13 +3,15 @@
|
|
|
3
3
|
// restart that adds it is offered (restart.ts).
|
|
4
4
|
import path from 'node:path';
|
|
5
5
|
import _ from 'lodash';
|
|
6
|
-
import {
|
|
6
|
+
import { openEngine } from '../../../host/engines/index.js';
|
|
7
|
+
import { containedMappings, containedPaths, providerFor, setNameOf, } from '../../../host/storage/index.js';
|
|
8
|
+
import { generateSandbox, GUEST, vgpuSource, vgpuWarning } from '../../../host/launch/index.js';
|
|
7
9
|
import { findSecretFiles } from '../../../host/profile/index.js';
|
|
8
10
|
import { RepoGuardStore } from '../../../host/guard/index.js';
|
|
9
11
|
import { hostPublicIp, prepareVpn, readVpnLine, vpnNotes } from '../../../host/vpn/index.js';
|
|
10
|
-
import { assertCanLaunch, isSandboxRunning, spawnDetached,
|
|
12
|
+
import { assertCanLaunch, isSandboxRunning, spawnDetached, probeHost, hideSandboxWindow, realContainedDeps, } from '../../../host/sandbox/index.js';
|
|
11
13
|
import { KnownProjects, ProjectRegistry } from '../../../host/projects/index.js';
|
|
12
|
-
import { LifeRecord, SessionLedger } from '../../../host/life/index.js';
|
|
14
|
+
import { LifeRecord, pageFileRisk, readHostMemory, SessionLedger, takePageFileHint } from '../../../host/life/index.js';
|
|
13
15
|
import { isWithin } from '../../../shared/paths/index.js';
|
|
14
16
|
import { watcherRunning } from '../../../sync/index.js';
|
|
15
17
|
import { protectionsOf } from '../../../core/local-config/index.js';
|
|
@@ -118,11 +120,39 @@ class Launcher {
|
|
|
118
120
|
}
|
|
119
121
|
/** One sandbox for this folder: resolve, prepare, write the launch files, then (unless generate) start it. */
|
|
120
122
|
async launchHere() {
|
|
121
|
-
const { ctx, generateOnly
|
|
123
|
+
const { ctx, generateOnly } = this;
|
|
122
124
|
const run = await this.resolve();
|
|
123
125
|
const { config } = run;
|
|
126
|
+
// An engine or storage kind that is not available yet stops here, before anything is prepared.
|
|
127
|
+
const engine = await openEngine(config);
|
|
128
|
+
const provider = providerFor(config, config.storage.contained === 'off'
|
|
129
|
+
? {}
|
|
130
|
+
: { contained: realContainedDeps(ctx.storageRoot, config.storage.containedMaxGb) });
|
|
124
131
|
if (!generateOnly)
|
|
125
132
|
assertCanLaunch(isSandboxRunning() ? runningOwner() : undefined);
|
|
133
|
+
// Contained storage: the image is mounted now (before anything reads or writes the data set), and let go of again
|
|
134
|
+
// when the launch fails before the sandbox starts. The background watcher holds it from then on.
|
|
135
|
+
const dataMappings = await this.prepareStorage(provider, run);
|
|
136
|
+
try {
|
|
137
|
+
return await this.launchPrepared(run, engine, dataMappings);
|
|
138
|
+
}
|
|
139
|
+
catch (e) {
|
|
140
|
+
await provider.release();
|
|
141
|
+
throw e;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
/** The data set's mappings from a contained-storage provider (mounting it), or undefined for plain folders. */
|
|
145
|
+
async prepareStorage(provider, run) {
|
|
146
|
+
if (provider.id === 'folder')
|
|
147
|
+
return undefined;
|
|
148
|
+
if (this.generateOnly)
|
|
149
|
+
return containedMappings(run.dataPath, containedPaths(run.storageRoot, setNameOf(run.dataPath)).mount, GUEST.data);
|
|
150
|
+
console.log('Mounting the contained storage (Windows asks for permission when it is not mounted yet)...');
|
|
151
|
+
return [...(await provider.prepare({ dataPath: run.dataPath, guest: GUEST.data })).mappings];
|
|
152
|
+
}
|
|
153
|
+
async launchPrepared(run, engine, dataMappings) {
|
|
154
|
+
const { ctx, generateOnly, extras } = this;
|
|
155
|
+
const { config } = run;
|
|
126
156
|
if (!generateOnly && !extras.extraProjects)
|
|
127
157
|
await maybeAddRoot(ctx, run);
|
|
128
158
|
const prepared = generateOnly ? null : await prepare(ctx, run);
|
|
@@ -136,8 +166,11 @@ class Launcher {
|
|
|
136
166
|
sandboxRunning: isSandboxRunning(),
|
|
137
167
|
base: run.workspaceHost,
|
|
138
168
|
});
|
|
169
|
+
// This PC's commit (RAM plus paging file) bounds the sandbox's memory as much as free RAM does.
|
|
170
|
+
const hostMemory = generateOnly ? null : readHostMemory(ctx.storageRoot);
|
|
139
171
|
const generated = generateSandbox({
|
|
140
172
|
packageRoot: ctx.packageRoot,
|
|
173
|
+
...(hostMemory ? { commitAvailableMb: hostMemory.commitAvailableMb } : {}),
|
|
141
174
|
run,
|
|
142
175
|
harnessArgs: this.options.passthrough,
|
|
143
176
|
probe: probeHost(config, run.harnessName),
|
|
@@ -145,10 +178,18 @@ class Launcher {
|
|
|
145
178
|
autoSession: extras.autoSession,
|
|
146
179
|
bootWants: bootWants.wants,
|
|
147
180
|
...(vpn ? { vpn } : {}),
|
|
148
|
-
|
|
181
|
+
...(dataMappings ? { dataMappings } : {}),
|
|
182
|
+
}, engine);
|
|
149
183
|
const notes = [...run.notes, ...bootWants.notes, ...generated.projects.notes, ...generated.mappingNotes];
|
|
150
184
|
for (const note of notes)
|
|
151
185
|
console.log(note);
|
|
186
|
+
if (generated.memoryNote)
|
|
187
|
+
console.log(c.yellow(generated.memoryNote));
|
|
188
|
+
if (generated.bootConfig.sandbox.vGpu)
|
|
189
|
+
console.log(c.yellow(vgpuWarning(vgpuSource(ctx.loaded.config.sandbox.vGpu))));
|
|
190
|
+
const risk = hostMemory ? pageFileRisk(hostMemory, generated.memoryMb) : null;
|
|
191
|
+
if (risk && takePageFileHint(ctx.storageRoot))
|
|
192
|
+
console.log(c.yellow(risk.text));
|
|
152
193
|
this.warnSecretFiles(run);
|
|
153
194
|
for (const line of vpnNotes(config.vpn))
|
|
154
195
|
console.log(c.yellow(line));
|
|
@@ -159,8 +200,7 @@ class Launcher {
|
|
|
159
200
|
const reopen = extras.extraProjects ? [] : await sessionsToResume(ctx, run);
|
|
160
201
|
this.record(run, generated);
|
|
161
202
|
this.share(generated);
|
|
162
|
-
|
|
163
|
-
await confirmSandboxStarted(generated.wsbPath);
|
|
203
|
+
await engine.start(generated.enginePlan);
|
|
164
204
|
this.startWatcher();
|
|
165
205
|
if (reopen.length)
|
|
166
206
|
await this.reopenAfterBoot(generated.launchId, reopen);
|
|
@@ -2,7 +2,7 @@ import path from 'node:path';
|
|
|
2
2
|
import fs from 'node:fs';
|
|
3
3
|
import { AccountStore } from '../../../host/profile/index.js';
|
|
4
4
|
import { SandboxChannel } from '../../../host/channel/index.js';
|
|
5
|
-
import { describePrune, pruneStorage } from '../../../host/storage/index.js';
|
|
5
|
+
import { describePrune, hostDataFolder, pruneStorage } from '../../../host/storage/index.js';
|
|
6
6
|
import { RepoGuardStore, readDataSize, saveMarkedProjects } from '../../../host/guard/index.js';
|
|
7
7
|
import { ensureConpty, ensureTerminal } from '../../../host/tools/index.js';
|
|
8
8
|
import { planView, viewSkipped, saveActiveViews, WorkspaceView } from '../../../host/workspace-view/index.js';
|
|
@@ -16,7 +16,7 @@ import { firstStartNotice, pendingDownloads } from './first-start.js';
|
|
|
16
16
|
import { LifeRecord, UPDATE_RESTART_WARNING, updateRestartPending } from '../../../host/life/index.js';
|
|
17
17
|
/** Nothing has been installed into this data set yet: the first start downloads every toolchain once. */
|
|
18
18
|
export function firstBoot(dataPath) {
|
|
19
|
-
return !fs.existsSync(path.join(dataPath, 'tools', 'resolved-versions.json'));
|
|
19
|
+
return !fs.existsSync(path.join(hostDataFolder(dataPath, 'tools'), 'resolved-versions.json'));
|
|
20
20
|
}
|
|
21
21
|
/** The first-start heads-up (also when this project needs tools not downloaded yet), or null. */
|
|
22
22
|
export function firstBootNotice(dataPath, generated) {
|
|
@@ -27,7 +27,7 @@ export function firstBootNotice(dataPath, generated) {
|
|
|
27
27
|
.map(([name]) => name),
|
|
28
28
|
...generated.databases.map((d) => d.database),
|
|
29
29
|
];
|
|
30
|
-
return firstStartNotice(firstBoot(dataPath), pendingDownloads(wanted, (dir) => fs.existsSync(path.join(dataPath, 'tools', dir))));
|
|
30
|
+
return firstStartNotice(firstBoot(dataPath), pendingDownloads(wanted, (dir) => fs.existsSync(path.join(hostDataFolder(dataPath, 'tools'), dir))));
|
|
31
31
|
}
|
|
32
32
|
function syncSummary(config, dataPath, workspaceHost) {
|
|
33
33
|
try {
|
|
@@ -17,7 +17,8 @@ const SESSION_START_MS = 60 * 60 * 1000;
|
|
|
17
17
|
export function attachHere(ctx, session) {
|
|
18
18
|
if (ctx.loaded.config.attach.autoHide && !insideSandbox())
|
|
19
19
|
void hideSandboxWindow(ctx.storageRoot, 120).catch(() => false);
|
|
20
|
-
|
|
20
|
+
// A copy in the agent reaches this PC's clipboard only when sandbox.clipboard already shares it with the sandbox.
|
|
21
|
+
return attachTerminal(session, { clipboardWrites: ctx.loaded.config.sandbox.clipboard });
|
|
21
22
|
}
|
|
22
23
|
/** The sandbox writes sandbox.json a few seconds into its boot; a second launch right after the first waits for it. */
|
|
23
24
|
export async function runningSandboxStatus(dataPath) {
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import type { Generated, ResolvedRun } from '../../../core/types.js';
|
|
2
|
+
import type { EnginePlan } from '../../../host/engines/index.js';
|
|
2
3
|
import type { Prepared } from './prepare.js';
|
|
3
4
|
/** What generateSandbox returned. */
|
|
4
5
|
export type GeneratedSandbox = Generated & {
|
|
5
6
|
readonly personalization: string;
|
|
7
|
+
readonly enginePlan: EnginePlan;
|
|
6
8
|
};
|
|
7
9
|
/** The launch summary rows, in the order they are printed. */
|
|
8
10
|
export declare function launchSummary(run: ResolvedRun, generated: GeneratedSandbox, prepared: Prepared | null): string[][];
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type ImportPlan } from '../../menu/settings/index.js';
|
|
2
|
+
import type { Context } from '../context.js';
|
|
3
|
+
/** The file `config export` writes when none is named. */
|
|
4
|
+
export declare const DEFAULT_EXPORT = "sandbox-settings.json";
|
|
5
|
+
/** Writes the settings that differ from the defaults (no secrets, no storage, no paths unless asked) to `file`. */
|
|
6
|
+
export declare function writeExport(ctx: Context, file: string, withPaths: boolean, overwrite: boolean): string[];
|
|
7
|
+
/** Reads a shared file and plans the import. Fails with the reason when it cannot be read. */
|
|
8
|
+
export declare function readImport(ctx: Context, file: string): ImportPlan;
|
|
9
|
+
/** Writes the planned changes to your settings file (comments stay); returns how many settings changed. */
|
|
10
|
+
export declare function applyImport(ctx: Context, plan: ImportPlan): number;
|
|
11
|
+
export declare function exportCommand(ctx: Context, file: string | undefined): number;
|
|
12
|
+
export declare function importCommand(ctx: Context, file: string | undefined): Promise<number>;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
// `sandbox config export` and `import`: your settings as a shareable .json, and a shared file read back in.
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { askRequired } from '../../../core/prompt.js';
|
|
5
|
+
import { fail, safeText, writeJson } from '../../../core/util/index.js';
|
|
6
|
+
import { c } from '../../output/index.js';
|
|
7
|
+
import { ConfigFile } from '../../../app/features/settings/index.js';
|
|
8
|
+
import { diffText, exportSettings, planImport, skippedLine } from '../../menu/settings/index.js';
|
|
9
|
+
/** The file `config export` writes when none is named. */
|
|
10
|
+
export const DEFAULT_EXPORT = 'sandbox-settings.json';
|
|
11
|
+
/** A shared file is a few KB; anything bigger is not one. */
|
|
12
|
+
const MAX_BYTES = 1024 * 1024;
|
|
13
|
+
/** Writes the settings that differ from the defaults (no secrets, no storage, no paths unless asked) to `file`. */
|
|
14
|
+
export function writeExport(ctx, file, withPaths, overwrite) {
|
|
15
|
+
const target = path.resolve(file);
|
|
16
|
+
if (!overwrite && fs.existsSync(target))
|
|
17
|
+
fail(target + ' exists already.', 'Pick another name, or delete it first.');
|
|
18
|
+
const { data, skipped } = exportSettings(ctx.loaded.config, withPaths);
|
|
19
|
+
fs.mkdirSync(path.dirname(target), { recursive: true });
|
|
20
|
+
writeJson(target, data);
|
|
21
|
+
return skipped.map(skippedLine);
|
|
22
|
+
}
|
|
23
|
+
/** Reads a shared file and plans the import. Fails with the reason when it cannot be read. */
|
|
24
|
+
export function readImport(ctx, file) {
|
|
25
|
+
const source = path.resolve(file);
|
|
26
|
+
if (!fs.existsSync(source))
|
|
27
|
+
fail('There is no file ' + source + '.', 'Give the path of a file made by sandbox config export.');
|
|
28
|
+
if (fs.statSync(source).size > MAX_BYTES)
|
|
29
|
+
fail(source + ' is too big to be a settings file.');
|
|
30
|
+
const plan = planImport(fs.readFileSync(source, 'utf8'), ctx.loaded.config);
|
|
31
|
+
if (plan.problems.length)
|
|
32
|
+
fail(source + ' is not valid settings:\n ' + plan.problems.map(safeText).join('\n '), 'Nothing was changed. Fix the file, or export a new one with: sandbox config export');
|
|
33
|
+
return plan;
|
|
34
|
+
}
|
|
35
|
+
/** Writes the planned changes to your settings file (comments stay); returns how many settings changed. */
|
|
36
|
+
export function applyImport(ctx, plan) {
|
|
37
|
+
const outcome = ConfigFile.user(ctx.loaded.configPath).setMany(plan.changes);
|
|
38
|
+
if (typeof outcome === 'object')
|
|
39
|
+
fail('Could not import: ' + outcome.problems.join('; '), 'Nothing was written. Your settings are unchanged.');
|
|
40
|
+
return plan.changes.length;
|
|
41
|
+
}
|
|
42
|
+
export function exportCommand(ctx, file) {
|
|
43
|
+
const target = file ?? DEFAULT_EXPORT;
|
|
44
|
+
const skipped = writeExport(ctx, target, ctx.options.withPaths, false);
|
|
45
|
+
console.log('Wrote ' + path.resolve(target) + ' (only what differs from the defaults).');
|
|
46
|
+
if (skipped.length) {
|
|
47
|
+
console.log('Left out:');
|
|
48
|
+
for (const line of skipped)
|
|
49
|
+
console.log(' ' + line);
|
|
50
|
+
}
|
|
51
|
+
if (!ctx.options.withPaths && skipped.some((s) => s.includes('folder or file')))
|
|
52
|
+
console.log("Keep this PC's folders and files in the file with --with-paths.");
|
|
53
|
+
return 0;
|
|
54
|
+
}
|
|
55
|
+
export async function importCommand(ctx, file) {
|
|
56
|
+
if (!file)
|
|
57
|
+
fail('Which file?', 'Usage: sandbox config import <file>');
|
|
58
|
+
const plan = readImport(ctx, file);
|
|
59
|
+
if (plan.skipped.length) {
|
|
60
|
+
console.log('Not imported (never taken from a file):');
|
|
61
|
+
for (const s of plan.skipped)
|
|
62
|
+
console.log(' ' + safeText(skippedLine(s)));
|
|
63
|
+
}
|
|
64
|
+
if (!plan.changes.length) {
|
|
65
|
+
console.log('Nothing to change: your settings already match the file.');
|
|
66
|
+
return 0;
|
|
67
|
+
}
|
|
68
|
+
console.log('This would change ' + plan.changes.length + ' setting' + (plan.changes.length === 1 ? '' : 's') + ':');
|
|
69
|
+
for (const line of diffText(plan.lines))
|
|
70
|
+
console.log(' ' + safeText(line));
|
|
71
|
+
const yes = ctx.options.yes ||
|
|
72
|
+
(await askRequired('Change your settings like this?', 'Add --yes to change them without asking.'));
|
|
73
|
+
if (!yes) {
|
|
74
|
+
console.log('Nothing was changed.');
|
|
75
|
+
return 0;
|
|
76
|
+
}
|
|
77
|
+
const n = applyImport(ctx, plan);
|
|
78
|
+
console.log(c.green('Imported ' + n + ' setting' + (n === 1 ? '' : 's') + '.') + ' New sandboxes use them.');
|
|
79
|
+
return 0;
|
|
80
|
+
}
|
|
@@ -2,7 +2,6 @@ import { spawn } from 'node:child_process';
|
|
|
2
2
|
import fs from 'node:fs';
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
import { pathToFileURL } from 'node:url';
|
|
5
|
-
import _ from 'lodash';
|
|
6
5
|
import { DEFAULTS, userConfigPath, userDir } from '../../../core/config/index.js';
|
|
7
6
|
import { redactSecrets } from '../../../core/schema/index.js';
|
|
8
7
|
import { allowedAnswer, allowStorePath, applyOverrides, describeOverrides, isTrusted, LOCAL_CONFIG_NAME, loosenedRequests, normalizeOverrides, OUTSIDE_FOLDER, outsideKey, outsideMappings, readLocalConfig, trustStorePath, } from '../../../core/local-config/index.js';
|
|
@@ -11,9 +10,8 @@ import { askChoice } from '../../../core/prompt.js';
|
|
|
11
10
|
import { dirExists, fail, safeText, writeJson } from '../../../core/util/index.js';
|
|
12
11
|
import { system32 } from '../../../shared/system.js';
|
|
13
12
|
import { refuseInSelfTest } from '../../../host/test-guard.js';
|
|
14
|
-
import { closest } from '../../validate.js';
|
|
15
13
|
import { c, nextStep, table } from '../../output/index.js';
|
|
16
|
-
import {
|
|
14
|
+
import { exportCommand, importCommand } from './config-share.js';
|
|
17
15
|
/** The settings file exists already: open it, start over, or leave it (no terminal: say how). */
|
|
18
16
|
async function existingFile(file) {
|
|
19
17
|
return askChoice(file + ' exists already.', [
|
|
@@ -43,79 +41,6 @@ async function initConfig() {
|
|
|
43
41
|
nextStep("sandbox config schema (editor help in every project's .sandbox-config.json)");
|
|
44
42
|
return 0;
|
|
45
43
|
}
|
|
46
|
-
/** The setting a key names, as the schema knows it; an unknown key says what is close. */
|
|
47
|
-
function settingNode(key) {
|
|
48
|
-
const root = ConfigFile.user(null).schema;
|
|
49
|
-
const keyPath = key.split('.');
|
|
50
|
-
let node = root;
|
|
51
|
-
for (const part of keyPath)
|
|
52
|
-
node = node?.child(part);
|
|
53
|
-
if (node)
|
|
54
|
-
return { path: keyPath, node };
|
|
55
|
-
const known = root.leaves().map((l) => l.key.join('.'));
|
|
56
|
-
const hint = closest(key, known);
|
|
57
|
-
return fail('There is no setting "' + key + '".' + (hint ? ' Did you mean ' + hint + '?' : ''), 'Settings are named like sandbox.memoryMb. See them all with: sandbox config show');
|
|
58
|
-
}
|
|
59
|
-
/** What was typed for a setting as the value it stands for: true/false/on/off, a number, JSON, or plain text. */
|
|
60
|
-
function settingValue(node, text) {
|
|
61
|
-
const word = text.trim().toLowerCase();
|
|
62
|
-
if (node.type === 'string')
|
|
63
|
-
return text;
|
|
64
|
-
if (node.type === 'boolean' || node.options.some((o) => o.type === 'boolean')) {
|
|
65
|
-
if (['true', 'on', 'yes'].includes(word))
|
|
66
|
-
return true;
|
|
67
|
-
if (['false', 'off', 'no'].includes(word))
|
|
68
|
-
return false;
|
|
69
|
-
}
|
|
70
|
-
try {
|
|
71
|
-
return JSON.parse(text);
|
|
72
|
-
}
|
|
73
|
-
catch {
|
|
74
|
-
// Not JSON: a bare word such as auto or a path is the text itself.
|
|
75
|
-
return node.type === 'array' ? text.split(',').map((t) => t.trim()) : text;
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
/** What a setting accepts, in words: its fixed values, a number and its range, true or false. */
|
|
79
|
-
function allowedText(node) {
|
|
80
|
-
const values = node.choiceValues.map((v) => String(v));
|
|
81
|
-
const open = node.openOption ?? (node.type === 'number' ? node : undefined);
|
|
82
|
-
const range = (n) => (n.rangeText() ? ' (' + n.rangeText() + ')' : '');
|
|
83
|
-
const more = open ? (open.type === 'number' ? 'a number' + range(open) : 'text') : '';
|
|
84
|
-
if (node.type === 'boolean')
|
|
85
|
-
return 'Use true or false.';
|
|
86
|
-
const parts = [...values, ...(more ? [more] : [])];
|
|
87
|
-
return parts.length ? 'Allowed: ' + parts.join(', or ') + '.' : 'Check the value.';
|
|
88
|
-
}
|
|
89
|
-
function setSettingCommand(ctx, key, text) {
|
|
90
|
-
if (!key || text === undefined)
|
|
91
|
-
fail('Which setting and value?', 'Usage: sandbox config set <setting> <value>');
|
|
92
|
-
const { path: keyPath, node } = settingNode(key);
|
|
93
|
-
if (node.isSection)
|
|
94
|
-
fail('"' + key + '" is a group of settings.', 'Set one of them, e.g. ' + node.leaves(keyPath)[0]?.key.join('.'));
|
|
95
|
-
const value = settingValue(node, text);
|
|
96
|
-
const problem = node.check(value);
|
|
97
|
-
if (problem !== true) {
|
|
98
|
-
fail('"' + text + '" does not work for ' + key + ': ' + problem, allowedText(node));
|
|
99
|
-
}
|
|
100
|
-
const outcome = ConfigFile.user(ctx.loaded.configPath).set(keyPath, value);
|
|
101
|
-
if (typeof outcome === 'object')
|
|
102
|
-
fail('Could not change ' + key + ': ' + outcome.problems.join('; '), 'Nothing was written.');
|
|
103
|
-
console.log(key +
|
|
104
|
-
' is ' +
|
|
105
|
-
JSON.stringify(_.get(redactSecrets(_.set({}, keyPath, value)), keyPath)) +
|
|
106
|
-
(outcome === 'unchanged' ? ' (it was already)' : '') +
|
|
107
|
-
'.');
|
|
108
|
-
return 0;
|
|
109
|
-
}
|
|
110
|
-
function getSettingCommand(ctx, key) {
|
|
111
|
-
if (!key)
|
|
112
|
-
fail('Which setting?', 'Usage: sandbox config get <setting> (all of them: sandbox config show)');
|
|
113
|
-
const { path: keyPath } = settingNode(key);
|
|
114
|
-
// Secret values (an agent's API keys) are never printed.
|
|
115
|
-
const value = _.get(redactSecrets(ctx.loaded.config), keyPath);
|
|
116
|
-
console.log(typeof value === 'string' ? value : JSON.stringify(value, null, 2));
|
|
117
|
-
return 0;
|
|
118
|
-
}
|
|
119
44
|
/**
|
|
120
45
|
* VS Code setting that maps every .sandbox-config.json (and the user config) to the local schema files, so project
|
|
121
46
|
* files need no "$schema" line and nothing is fetched from the internet (remote schemas need trusting).
|
|
@@ -208,7 +133,8 @@ function previewFolders(ctx, dir, filePath, overrides) {
|
|
|
208
133
|
}
|
|
209
134
|
}
|
|
210
135
|
export function config(ctx) {
|
|
211
|
-
|
|
136
|
+
// get, set, reset and list are the settings feature's operations (cli/operations runs them before this).
|
|
137
|
+
const [action = 'summary', key] = ctx.options.positionals;
|
|
212
138
|
switch (action) {
|
|
213
139
|
case 'summary':
|
|
214
140
|
table([
|
|
@@ -233,15 +159,15 @@ export function config(ctx) {
|
|
|
233
159
|
case 'show':
|
|
234
160
|
console.log(JSON.stringify(redactSecrets(ctx.loaded.config), null, 2));
|
|
235
161
|
return 0;
|
|
236
|
-
case '
|
|
237
|
-
return
|
|
238
|
-
case '
|
|
239
|
-
return
|
|
162
|
+
case 'export':
|
|
163
|
+
return exportCommand(ctx, key);
|
|
164
|
+
case 'import':
|
|
165
|
+
return importCommand(ctx, key);
|
|
240
166
|
case 'schema':
|
|
241
167
|
return printSchemaSettings();
|
|
242
168
|
case 'check':
|
|
243
169
|
return checkLocalConfig(ctx);
|
|
244
170
|
default:
|
|
245
|
-
fail('Unknown config action "' + action + '".', 'Use one of: sandbox config show | get | set | path | init | schema | check');
|
|
171
|
+
fail('Unknown config action "' + action + '".', 'Use one of: sandbox config show | list | get | set | reset | path | init | schema | check | export | import');
|
|
246
172
|
}
|
|
247
173
|
}
|
|
@@ -1,6 +1,20 @@
|
|
|
1
1
|
import { sleep } from '../../../core/util/index.js';
|
|
2
|
+
import { newestCrashReport } from '../../../host/life/index.js';
|
|
2
3
|
import { LogsService } from '../../services/index.js';
|
|
4
|
+
/** The newest crash report (written by the background sync when the sandbox or this PC went down). */
|
|
5
|
+
function printCrashReport(ctx) {
|
|
6
|
+
const report = newestCrashReport(ctx.storageRoot);
|
|
7
|
+
if (!report) {
|
|
8
|
+
console.log('No crash report yet: no sandbox has ended in a crash since this was installed.');
|
|
9
|
+
return 0;
|
|
10
|
+
}
|
|
11
|
+
console.log('== ' + report.file + ' ==');
|
|
12
|
+
console.log(report.text);
|
|
13
|
+
return 0;
|
|
14
|
+
}
|
|
3
15
|
export async function logs(ctx) {
|
|
16
|
+
if (ctx.options.crash)
|
|
17
|
+
return printCrashReport(ctx);
|
|
4
18
|
const service = new LogsService(ctx);
|
|
5
19
|
const file = service.newest();
|
|
6
20
|
console.log('== ' + file + ' ==');
|
|
@@ -2,10 +2,11 @@ import { launch } from './launch/index.js';
|
|
|
2
2
|
import { setup } from './setup/index.js';
|
|
3
3
|
import { data } from './data/index.js';
|
|
4
4
|
import { storage } from './storage/index.js';
|
|
5
|
-
import { attach, db, exec
|
|
5
|
+
import { attach, db, exec } from './sessions/index.js';
|
|
6
6
|
import { account } from './accounts.js';
|
|
7
7
|
import { projects } from './projects/index.js';
|
|
8
8
|
import { audit, claudeHost, clean, config, doctor, hostCommand, logs, migrate, sync, watcher, } from './maintenance/index.js';
|
|
9
|
+
import { engine } from './engine.js';
|
|
9
10
|
import { resume } from './resume.js';
|
|
10
11
|
import { agentCommandsCommand } from './agent-commands.js';
|
|
11
12
|
import { vpn } from './vpn.js';
|
|
@@ -14,16 +15,10 @@ export const HANDLERS = {
|
|
|
14
15
|
launch: (ctx) => launch(ctx),
|
|
15
16
|
generate: (ctx) => launch(ctx, true),
|
|
16
17
|
attach: attach,
|
|
17
|
-
sessions: sessions,
|
|
18
|
-
status: status,
|
|
19
18
|
exec: exec,
|
|
20
19
|
'agent-commands': agentCommandsCommand,
|
|
21
20
|
db: db,
|
|
22
|
-
restart: restart,
|
|
23
21
|
resume: resume,
|
|
24
|
-
stop: stop,
|
|
25
|
-
show: show,
|
|
26
|
-
hide: hide,
|
|
27
22
|
account: account,
|
|
28
23
|
projects: projects,
|
|
29
24
|
sync: sync,
|
|
@@ -36,6 +31,7 @@ export const HANDLERS = {
|
|
|
36
31
|
setup: setup,
|
|
37
32
|
data: data,
|
|
38
33
|
storage: storage,
|
|
34
|
+
engine: engine,
|
|
39
35
|
'host-claude': claudeHost,
|
|
40
36
|
host: hostCommand,
|
|
41
37
|
_watch: watcher,
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
// Contained storage (beta): the image is there, what the record says is mounted matches what is really mounted, and
|
|
2
|
+
// the folders around the image are private. A mount left behind (a sandbox that ended without letting go, a crash) is
|
|
3
|
+
// dismounted here, which needs the Windows permission prompt.
|
|
4
|
+
import fs from 'node:fs';
|
|
5
|
+
import { isWin } from '../../../../core/util/index.js';
|
|
6
|
+
import { parseIcacls, privacyProblems, SHARING_GROUP } from '../../../../host/health/index.js';
|
|
7
|
+
import { realContainedDeps } from '../../../../host/sandbox/index.js';
|
|
8
|
+
import { protectPrivateFolder } from '../../../../host/sharing/index.js';
|
|
9
|
+
import { containedAvailability, ContainedStorage, containedPaths } from '../../../../host/storage/index.js';
|
|
10
|
+
import { ok } from './common.js';
|
|
11
|
+
function storageOf(env) {
|
|
12
|
+
const { config } = env.ctx.loaded;
|
|
13
|
+
return new ContainedStorage(realContainedDeps(env.storageRoot, config.storage.containedMaxGb), config.storage.dataName);
|
|
14
|
+
}
|
|
15
|
+
/** Only when contained storage is on, or an image or a record of one exists. */
|
|
16
|
+
const inUse = (env) => {
|
|
17
|
+
if (!isWin)
|
|
18
|
+
return false;
|
|
19
|
+
const { config } = env.ctx.loaded;
|
|
20
|
+
const paths = containedPaths(env.storageRoot, config.storage.dataName);
|
|
21
|
+
return config.storage.contained === 'vhdx' || fs.existsSync(paths.image) || fs.existsSync(paths.stateFile);
|
|
22
|
+
};
|
|
23
|
+
export const CONTAINED_CHECKS = [
|
|
24
|
+
{
|
|
25
|
+
id: 'data-contained',
|
|
26
|
+
group: 'Data folder',
|
|
27
|
+
name: 'Contained storage',
|
|
28
|
+
checking: 'the contained storage image (beta)',
|
|
29
|
+
applies: inUse,
|
|
30
|
+
timeoutMs: 60_000,
|
|
31
|
+
run: async (env) => {
|
|
32
|
+
const wanted = env.ctx.loaded.config.storage.contained === 'vhdx';
|
|
33
|
+
const available = containedAvailability();
|
|
34
|
+
if (!available.available)
|
|
35
|
+
return wanted
|
|
36
|
+
? {
|
|
37
|
+
status: 'needs-you',
|
|
38
|
+
detail: 'storage.contained is "vhdx", but ' + available.reasons.join(' '),
|
|
39
|
+
means: 'A launch cannot mount the image on this PC.',
|
|
40
|
+
fix: available.fixes.join(' '),
|
|
41
|
+
}
|
|
42
|
+
: {
|
|
43
|
+
status: 'skipped',
|
|
44
|
+
detail: 'an image exists, but this PC cannot look at it: ' + available.reasons.join(' '),
|
|
45
|
+
};
|
|
46
|
+
const storage = storageOf(env);
|
|
47
|
+
const diagnosis = await storage.diagnose();
|
|
48
|
+
switch (diagnosis.kind) {
|
|
49
|
+
case 'image-missing':
|
|
50
|
+
return wanted
|
|
51
|
+
? {
|
|
52
|
+
status: 'needs-you',
|
|
53
|
+
detail: 'the image is missing: ' + storage.paths.image,
|
|
54
|
+
means: 'A launch stops until it is there (the tools, state and logs in it are gone with it).',
|
|
55
|
+
fix: 'Restore the file, or run: sandbox storage contained off (and then on again for a new, empty image).',
|
|
56
|
+
}
|
|
57
|
+
: ok('no image (contained storage is off)');
|
|
58
|
+
case 'in-use':
|
|
59
|
+
return ok('mounted, in use by a running sandbox');
|
|
60
|
+
case 'stale-mount':
|
|
61
|
+
return {
|
|
62
|
+
status: 'needs-you',
|
|
63
|
+
detail: 'the image is still mounted at ' + storage.paths.mount + ', and nothing uses it',
|
|
64
|
+
means: 'It stays attached to this PC until it is dismounted; a launch would reuse it.',
|
|
65
|
+
plan: 'dismount the image (Windows asks for permission)',
|
|
66
|
+
data: 'dismount',
|
|
67
|
+
};
|
|
68
|
+
case 'stale-state':
|
|
69
|
+
return {
|
|
70
|
+
status: 'warn',
|
|
71
|
+
detail: 'the record says the image is mounted, but it is not',
|
|
72
|
+
means: 'Nothing is wrong with the image; the record is out of date.',
|
|
73
|
+
plan: 'correct the record',
|
|
74
|
+
data: 'record',
|
|
75
|
+
};
|
|
76
|
+
default:
|
|
77
|
+
return ok('not mounted' + (wanted ? '' : ' (contained storage is off; the image is kept)'));
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
fix: async (env, finding) => {
|
|
81
|
+
const storage = storageOf(env);
|
|
82
|
+
if (finding.data === 'record') {
|
|
83
|
+
storage.clearRecord();
|
|
84
|
+
return { done: 'corrected the record' };
|
|
85
|
+
}
|
|
86
|
+
const result = await storage.dismountIfIdle();
|
|
87
|
+
if (!result.dismounted)
|
|
88
|
+
throw new Error('Could not dismount the image: ' + (result.note ?? 'unknown reason'));
|
|
89
|
+
return { done: 'dismounted the image' };
|
|
90
|
+
},
|
|
91
|
+
needsIdle: 'fix',
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
id: 'data-contained-privacy',
|
|
95
|
+
group: 'Data folder',
|
|
96
|
+
name: 'Contained storage folders',
|
|
97
|
+
checking: 'who can open the contained storage folders',
|
|
98
|
+
applies: inUse,
|
|
99
|
+
run: (env) => {
|
|
100
|
+
const { config } = env.ctx.loaded;
|
|
101
|
+
const paths = containedPaths(env.storageRoot, config.storage.dataName);
|
|
102
|
+
// While mounted, the mount folder shows the image's own root, and nothing is changed under a mount point.
|
|
103
|
+
if (env.running)
|
|
104
|
+
return ok('a sandbox is running; not looked at now');
|
|
105
|
+
const loose = [];
|
|
106
|
+
for (const dir of [paths.imagesDir, paths.mountsDir, paths.mount]) {
|
|
107
|
+
if (!fs.existsSync(dir))
|
|
108
|
+
continue;
|
|
109
|
+
const text = env.system.icacls(dir);
|
|
110
|
+
if (text === null)
|
|
111
|
+
return { status: 'skipped', detail: 'could not read the permissions of ' + dir };
|
|
112
|
+
const problems = privacyProblems(parseIcacls(text, dir), SHARING_GROUP);
|
|
113
|
+
if (problems.length > 0)
|
|
114
|
+
loose.push(dir + ' (' + problems.join(', ') + ')');
|
|
115
|
+
}
|
|
116
|
+
if (loose.length === 0)
|
|
117
|
+
return ok('private (you, SYSTEM and administrators)');
|
|
118
|
+
return {
|
|
119
|
+
status: 'warn',
|
|
120
|
+
detail: 'open to more than you: ' + loose.join('; '),
|
|
121
|
+
means: 'Other users of this PC could open the image or the folders it is mounted in.',
|
|
122
|
+
plan: 'make them private',
|
|
123
|
+
data: 'private',
|
|
124
|
+
};
|
|
125
|
+
},
|
|
126
|
+
fix: (env) => {
|
|
127
|
+
const { config } = env.ctx.loaded;
|
|
128
|
+
const paths = containedPaths(env.storageRoot, config.storage.dataName);
|
|
129
|
+
// Never with an image mounted below: a folder with files is walked, and a mount point must not be.
|
|
130
|
+
if (env.running)
|
|
131
|
+
throw new Error('a sandbox is running; run repair again once it is closed');
|
|
132
|
+
for (const dir of [paths.imagesDir, paths.mountsDir, paths.mount])
|
|
133
|
+
if (fs.existsSync(dir))
|
|
134
|
+
protectPrivateFolder(dir);
|
|
135
|
+
return { done: 'made the folders private' };
|
|
136
|
+
},
|
|
137
|
+
needsIdle: 'fix',
|
|
138
|
+
},
|
|
139
|
+
];
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type HcsProbes } from '../../../../host/engines/index.js';
|
|
2
|
+
import type { Check } from '../types.js';
|
|
3
|
+
/** Replaceable by tests: the probes the row looks through. */
|
|
4
|
+
export declare const HCS_PROBES: {
|
|
5
|
+
current: HcsProbes | null;
|
|
6
|
+
};
|
|
7
|
+
export declare const HCS_CHECKS: Check[];
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// The HCS engine (alpha), only when sandbox.engine is "hcs": can this PC run it. Looks only; the fixes are commands for
|
|
2
|
+
// you to run (they change Windows), never run by repair.
|
|
3
|
+
import { checkHcs, realHcsProbes } from '../../../../host/engines/index.js';
|
|
4
|
+
import { ok } from './common.js';
|
|
5
|
+
const hcsInUse = (env) => env.ctx.loaded.config.sandbox.engine === 'hcs';
|
|
6
|
+
/** Replaceable by tests: the probes the row looks through. */
|
|
7
|
+
export const HCS_PROBES = { current: null };
|
|
8
|
+
export const HCS_CHECKS = [
|
|
9
|
+
{
|
|
10
|
+
id: 'hcs-engine',
|
|
11
|
+
group: 'Sandbox',
|
|
12
|
+
name: 'HCS engine (alpha)',
|
|
13
|
+
checking: 'the HCS engine',
|
|
14
|
+
applies: hcsInUse,
|
|
15
|
+
timeoutMs: 60000,
|
|
16
|
+
run: () => {
|
|
17
|
+
const check = checkHcs(HCS_PROBES.current ?? realHcsProbes());
|
|
18
|
+
if (check.available)
|
|
19
|
+
return ok('this PC can run it (starting it is not enabled yet in this alpha)');
|
|
20
|
+
return {
|
|
21
|
+
status: 'needs-you',
|
|
22
|
+
detail: check.reasons.length + ' thing(s) missing: ' + check.reasons[0],
|
|
23
|
+
means: check.reasons.join(' '),
|
|
24
|
+
fix: check.fixes.join(' | '),
|
|
25
|
+
};
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
];
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { AGENT_CHECKS } from './agents.js';
|
|
2
|
+
import { CONTAINED_CHECKS } from './contained.js';
|
|
2
3
|
import { DATA_CHECKS } from './data.js';
|
|
4
|
+
import { HCS_CHECKS } from './hcs.js';
|
|
3
5
|
import { INSTALL_CHECKS } from './install.js';
|
|
4
6
|
import { MACHINE_CHECKS } from './machine.js';
|
|
5
7
|
import { NETWORK_CHECKS } from './network.js';
|
|
@@ -12,8 +14,10 @@ export const ALL_CHECKS = [
|
|
|
12
14
|
...INSTALL_CHECKS,
|
|
13
15
|
...MACHINE_CHECKS,
|
|
14
16
|
...DATA_CHECKS,
|
|
17
|
+
...CONTAINED_CHECKS,
|
|
15
18
|
...SETTINGS_CHECKS,
|
|
16
19
|
...SANDBOX_CHECKS,
|
|
20
|
+
...HCS_CHECKS,
|
|
17
21
|
...AGENT_CHECKS,
|
|
18
22
|
...NETWORK_CHECKS,
|
|
19
23
|
...VPN_CHECKS,
|