windows-development-sandbox 1.5.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/README.md +1 -0
- package/config.example.json +27 -1
- 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} +4 -0
- package/dist/{cli/menu/settings/categories.js → app/features/settings/categories.def.js} +40 -46
- 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/{cli/menu/settings → app/kernel}/schema-node.d.ts +9 -0
- package/dist/{cli/menu/settings → app/kernel}/schema-node.js +26 -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 +18 -2
- package/dist/cli/args.js +101 -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/engine.d.ts +2 -0
- package/dist/cli/commands/engine.js +60 -0
- package/dist/cli/commands/index.d.ts +2 -1
- package/dist/cli/commands/index.js +2 -1
- 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 +102 -9
- package/dist/cli/commands/launch/prepare.js +6 -4
- package/dist/cli/commands/launch/running.js +2 -1
- package/dist/cli/commands/launch/summary.d.ts +2 -0
- 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-share.d.ts +12 -0
- package/dist/cli/commands/maintenance/config-share.js +80 -0
- package/dist/cli/commands/maintenance/config.d.ts +1 -1
- package/dist/cli/commands/maintenance/config.js +38 -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/logs.js +14 -0
- 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 +10 -7
- 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/contained.d.ts +2 -0
- package/dist/cli/commands/repair/checks/contained.js +139 -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/hcs.d.ts +7 -0
- package/dist/cli/commands/repair/checks/hcs.js +28 -0
- package/dist/cli/commands/repair/checks/index.d.ts +2 -0
- package/dist/cli/commands/repair/checks/index.js +24 -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 +86 -0
- package/dist/cli/commands/repair/checks/sandbox.d.ts +2 -0
- package/dist/cli/commands/repair/checks/sandbox.js +282 -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 +78 -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 +50 -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/index.d.ts +0 -4
- package/dist/cli/commands/sessions/index.js +3 -7
- package/dist/cli/commands/setup/index.d.ts +5 -0
- package/dist/cli/commands/setup/index.js +25 -1
- 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/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 +91 -0
- package/dist/cli/commands/storage/storage.d.ts +8 -0
- package/dist/cli/commands/storage/storage.js +179 -0
- package/dist/cli/commands/user-config.js +2 -2
- package/dist/cli/commands/vpn.d.ts +4 -0
- package/dist/cli/commands/vpn.js +91 -0
- package/dist/cli/commands/web.d.ts +4 -0
- package/dist/cli/commands/web.js +97 -0
- package/dist/cli/history.js +1 -1
- package/dist/cli/index.js +48 -4
- package/dist/cli/manifest.d.ts +339 -97
- package/dist/cli/manifest.js +222 -67
- 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 +38 -3
- package/dist/cli/menu/apps.js +80 -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/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 +11 -2
- package/dist/cli/menu/menu.js +36 -15
- package/dist/cli/menu/pages/accounts-page.js +55 -24
- package/dist/cli/menu/pages/agents-page.d.ts +68 -0
- package/dist/cli/menu/pages/agents-page.js +345 -0
- package/dist/cli/menu/pages/apps-page.d.ts +3 -1
- package/dist/cli/menu/pages/apps-page.js +20 -4
- package/dist/cli/menu/pages/list-page.d.ts +43 -3
- package/dist/cli/menu/pages/list-page.js +146 -12
- package/dist/cli/menu/pages/maintenance-page.d.ts +9 -5
- package/dist/cli/menu/pages/maintenance-page.js +172 -85
- package/dist/cli/menu/pages/sandbox-page.d.ts +7 -6
- package/dist/cli/menu/pages/sandbox-page.js +117 -120
- package/dist/cli/menu/pages/scopes.d.ts +1 -1
- package/dist/cli/menu/pages/sessions-page.d.ts +6 -8
- package/dist/cli/menu/pages/sessions-page.js +22 -75
- package/dist/cli/menu/pages/settings-page.d.ts +10 -14
- package/dist/cli/menu/pages/settings-page.js +95 -102
- package/dist/cli/menu/render-view.d.ts +28 -0
- package/dist/cli/menu/render-view.js +112 -0
- package/dist/cli/menu/settings/ask-path.d.ts +14 -0
- package/dist/cli/menu/settings/ask-path.js +14 -0
- package/dist/cli/menu/settings/collections/collection-editor.d.ts +8 -2
- 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 +10 -1
- package/dist/cli/menu/settings/collections/string-list-editor.js +23 -0
- 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 +6 -2
- package/dist/cli/menu/settings/object-editor.js +15 -4
- 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 +10 -1
- package/dist/cli/menu/settings/value-editor.js +99 -63
- package/dist/cli/menu/several.js +7 -5
- 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 +53 -10
- package/dist/cli/menu/shell.js +115 -10
- package/dist/cli/menu/views.d.ts +7 -0
- package/dist/cli/menu/views.js +11 -0
- package/dist/cli/menu/vpn-login.d.ts +16 -0
- package/dist/cli/menu/vpn-login.js +74 -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 +5 -1
- package/dist/cli/output/print.js +15 -4
- 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/accounts-service.d.ts +2 -0
- package/dist/cli/services/accounts-service.js +2 -2
- 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/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/logs-service.js +4 -3
- 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 +12 -4
- package/dist/cli/tui/app.js +38 -9
- 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 +28 -2
- package/dist/cli/tui/list/list-screen.js +130 -66
- package/dist/cli/tui/list/list-types.d.ts +10 -4
- package/dist/cli/tui/nav.d.ts +29 -0
- package/dist/cli/tui/nav.js +67 -0
- package/dist/cli/tui/terminal.d.ts +7 -0
- package/dist/cli/tui/terminal.js +30 -10
- 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 +13 -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 +36 -0
- package/dist/core/schema/config.js +26 -2
- package/dist/core/schema/harness.d.ts +2 -0
- package/dist/core/schema/harness.js +13 -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.d.ts +6 -0
- package/dist/core/schema/sandbox.js +21 -3
- package/dist/core/schema/vpn.d.ts +18 -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 +44 -0
- 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 +54 -0
- package/dist/guest/agents/agent-files.js +67 -0
- package/dist/guest/agents/agent-installer.js +2 -9
- package/dist/guest/agents/local-state.d.ts +14 -0
- package/dist/guest/agents/local-state.js +218 -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 +51 -11
- package/dist/guest/daemon/daemon.js +8 -1
- package/dist/guest/daemon/exec.js +2 -1
- package/dist/guest/daemon/idle-shutdown.js +2 -0
- package/dist/guest/daemon/sessions.d.ts +5 -0
- package/dist/guest/daemon/sessions.js +20 -3
- package/dist/guest/entries/agent.d.ts +1 -0
- package/dist/guest/entries/agent.js +10 -0
- package/dist/guest/entries/daemon.js +5 -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 +2 -0
- package/dist/guest/runtime/csc.js +2 -0
- package/dist/guest/runtime/secrets.d.ts +12 -0
- package/dist/guest/runtime/secrets.js +63 -0
- package/dist/guest/sessions/viewer.js +3 -1
- 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/native/rust-extras.js +4 -2
- 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 +174 -0
- 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 +6 -2
- package/dist/host/channel/attach.js +6 -3
- package/dist/host/channel/channel.d.ts +9 -0
- package/dist/host/channel/channel.js +30 -2
- 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/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.d.ts +5 -1
- package/dist/host/launch/generate.js +73 -7
- 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 +11 -2
- package/dist/host/launch/stage.js +1 -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/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/native.d.ts +3 -2
- package/dist/host/native.js +22 -3
- 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/claude-login.js +3 -2
- 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/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 +4 -0
- package/dist/host/sandbox/platform.js +23 -4
- package/dist/host/sandbox/tasklist.d.ts +13 -0
- package/dist/host/sandbox/tasklist.js +47 -0
- 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 +94 -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 +8 -3
- 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/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/history.d.ts +21 -0
- package/dist/host/storage/history.js +49 -0
- package/dist/host/storage/index.d.ts +6 -0
- package/dist/host/storage/index.js +6 -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/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/storage/root.d.ts +18 -0
- package/dist/host/storage/root.js +77 -0
- package/dist/host/tools/conpty.js +3 -2
- package/dist/host/tools/windows-terminal.d.ts +2 -0
- package/dist/host/tools/windows-terminal.js +31 -12
- 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 +19 -0
- package/dist/host/vpn/prepare.js +138 -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 +3 -0
- package/dist/host/web/browser.js +23 -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 +10 -0
- package/dist/host/web/index.js +9 -0
- package/dist/host/web/rpc.d.ts +24 -0
- package/dist/host/web/rpc.js +149 -0
- package/dist/host/web/runner.d.ts +16 -0
- package/dist/host/web/runner.js +44 -0
- package/dist/host/web/server.d.ts +47 -0
- package/dist/host/web/server.js +238 -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 +27675 -0
- package/dist/runtime/daemon.js +1950 -1122
- package/dist/runtime/db.js +302 -111
- package/dist/runtime/main.js +1560 -275
- package/dist/runtime/netproxy.js +168 -8
- package/dist/runtime/view.js +186 -13
- 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 +125 -0
- package/dist/selftest/app.test.d.ts +2 -0
- package/dist/selftest/app.test.js +324 -0
- package/dist/selftest/channel.test.js +18 -0
- package/dist/selftest/cli.test.js +35 -4
- 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.d.ts +2 -0
- package/dist/selftest/credentials.test.js +198 -0
- package/dist/selftest/engine.test.d.ts +2 -0
- package/dist/selftest/engine.test.js +127 -0
- package/dist/selftest/generate.test.js +1 -1
- package/dist/selftest/hcs.test.d.ts +2 -0
- package/dist/selftest/hcs.test.js +482 -0
- package/dist/selftest/health.test.d.ts +2 -0
- package/dist/selftest/health.test.js +470 -0
- package/dist/selftest/heavy-load.test.d.ts +2 -0
- package/dist/selftest/heavy-load.test.js +329 -0
- package/dist/selftest/host-sim.test.js +2 -0
- package/dist/selftest/index.js +31 -0
- package/dist/selftest/layout.test.js +14 -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.d.ts +7 -0
- package/dist/selftest/menu-screens.js +68 -17
- package/dist/selftest/menu.test.js +603 -22
- 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/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 +20 -0
- package/dist/selftest/support/hcs-probes.d.ts +17 -0
- package/dist/selftest/support/hcs-probes.js +41 -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 +412 -0
- package/dist/selftest/web.test.d.ts +2 -0
- package/dist/selftest/web.test.js +402 -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 +9 -1
- package/dist/shared/channel/run-dir.js +18 -1
- package/dist/shared/channel/schema.d.ts +53 -0
- package/dist/shared/channel/schema.js +38 -0
- package/dist/shared/channel/secrets.d.ts +29 -0
- package/dist/shared/channel/secrets.js +50 -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 +29 -0
- package/dist/shared/vpn/download.js +30 -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/vpn/wireguard.d.ts +51 -0
- package/dist/shared/vpn/wireguard.js +227 -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 +9 -5
- package/dist/sync/sync-state.d.ts +1 -0
- package/dist/sync/sync-state.js +1 -0
- package/dist/sync/watcher.d.ts +13 -0
- package/dist/sync/watcher.js +102 -3
- package/dist/web/index.html +14 -0
- package/dist/web/main-NRRS5O6Z.js +157 -0
- package/dist/web/main-T5DMCHYV.css +1 -0
- package/native/csharp/FolderSecurity.cs +29 -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/protect-data.ps1 +29 -0
- package/native/scripts/read-folder-sddl.ps1 +10 -0
- package/native/scripts/run-elevated.ps1 +17 -4
- package/native/scripts/set-folder-access.ps1 +49 -7
- package/native/scripts/stop-events.ps1 +23 -8
- 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 +22 -5
- package/sandbox/csharp/EnvBroadcast.cs +33 -0
- package/sandbox/csharp/MemGov.cs +398 -0
- package/sandbox/csharp/PathSync.cs +90 -0
- package/sandbox/csharp/PtyHost.cs +111 -5
- package/sandbox/scripts/install-shell-path.ps1 +73 -0
- package/sandbox/scripts/set-machine-environment.ps1 +37 -4
- package/schemas/config.schema.json +136 -7
- package/schemas/sandbox-config.schema.json +17 -4
- package/dist/cli/commands/repair/checks.d.ts +0 -2
- package/dist/cli/commands/repair/checks.js +0 -246
- 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 -45
- package/dist/cli/commands/sessions/status.d.ts +0 -2
- package/dist/cli/commands/sessions/status.js +0 -93
- package/dist/cli/commands/sessions/window.d.ts +0 -3
- package/dist/cli/commands/sessions/window.js +0 -18
- 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
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/** A copy is estimated at this speed, plus a cost per file (small files are slower than big ones). */
|
|
2
|
+
export declare const COPY_BYTES_PER_SECOND: number;
|
|
3
|
+
export declare const COPY_SECONDS_PER_FILE = 0.002;
|
|
4
|
+
/** Above these a move is called big: the dialog and the command warn. */
|
|
5
|
+
export declare const BIG_BYTES: number;
|
|
6
|
+
export declare const BIG_FILES = 200000;
|
|
7
|
+
/** Measuring stops after this long or this many entries and reports "at least". */
|
|
8
|
+
export declare const MEASURE_MS = 20000;
|
|
9
|
+
export declare const MEASURE_ENTRIES = 3000000;
|
|
10
|
+
export interface Measured {
|
|
11
|
+
readonly bytes: number;
|
|
12
|
+
readonly files: number;
|
|
13
|
+
/** The walk stopped at its limit: the real size is at least this. */
|
|
14
|
+
readonly partial: boolean;
|
|
15
|
+
}
|
|
16
|
+
export interface MoveEstimate {
|
|
17
|
+
/** The same drive: folders are renamed, nothing is copied. */
|
|
18
|
+
readonly sameVolume: boolean;
|
|
19
|
+
readonly seconds: number;
|
|
20
|
+
readonly freeBytes: number | null;
|
|
21
|
+
/** Room on the target drive (always true for a rename). */
|
|
22
|
+
readonly fits: boolean;
|
|
23
|
+
readonly big: boolean;
|
|
24
|
+
}
|
|
25
|
+
export interface MoveProgress {
|
|
26
|
+
readonly bytes: number;
|
|
27
|
+
readonly files: number;
|
|
28
|
+
}
|
|
29
|
+
export interface MoveOptions {
|
|
30
|
+
/** Copy even on the same drive (tests, and --keep-old which needs the old folder to stay). */
|
|
31
|
+
readonly forceCopy?: boolean;
|
|
32
|
+
readonly keepOld?: boolean;
|
|
33
|
+
readonly onProgress?: (progress: MoveProgress) => void;
|
|
34
|
+
}
|
|
35
|
+
export interface MoveResult {
|
|
36
|
+
readonly from: string;
|
|
37
|
+
readonly to: string;
|
|
38
|
+
readonly copied: boolean;
|
|
39
|
+
readonly files: number;
|
|
40
|
+
readonly bytes: number;
|
|
41
|
+
/** What was stored as storage.root. */
|
|
42
|
+
readonly pinned: string;
|
|
43
|
+
/** The old folder is gone (false with keepOld, when links were left in it, or when removing failed). */
|
|
44
|
+
readonly removedOld: boolean;
|
|
45
|
+
readonly notes: readonly string[];
|
|
46
|
+
}
|
|
47
|
+
/** Size and file count, never following links or junctions, with a time and entry limit. */
|
|
48
|
+
export declare function measureFolder(root: string, maxMs?: number, maxEntries?: number): Measured;
|
|
49
|
+
/** Do both folders (the target may not exist yet) sit on the same volume? */
|
|
50
|
+
export declare function sameVolume(from: string, to: string): boolean;
|
|
51
|
+
/** The pure part of the estimate: time, room and whether it is big. `freeBytes` null = unknown (assumed enough). */
|
|
52
|
+
export declare function estimateMove(measured: Measured, same: boolean, freeBytes: number | null): MoveEstimate;
|
|
53
|
+
export declare function estimate(from: string, to: string, measured: Measured, copyOnly?: boolean): MoveEstimate;
|
|
54
|
+
/** "about 3 minutes", "a few seconds". */
|
|
55
|
+
export declare function describeDuration(seconds: number): string;
|
|
56
|
+
/** "12.3 GB, 412,000 files", with "at least" when the measuring stopped early. */
|
|
57
|
+
export declare function describeSize(measured: Measured): string;
|
|
58
|
+
/** A warning line for a big or too-big move, or null. */
|
|
59
|
+
export declare function moveWarning(measured: Measured, est: MoveEstimate): string | null;
|
|
60
|
+
/** What to store in config.json for this folder: the %VARIABLE% form when it is a default, else the full path. */
|
|
61
|
+
export declare function pinValue(folder: string, env?: NodeJS.ProcessEnv): string;
|
|
62
|
+
/** Why `from` -> `to` is not allowed, or null. `allowNonEmpty`: the target may hold data already (switching to it). */
|
|
63
|
+
export declare function moveProblem(from: string, to: string, allowNonEmpty?: boolean): {
|
|
64
|
+
message: string;
|
|
65
|
+
fix: string;
|
|
66
|
+
} | null;
|
|
67
|
+
export declare class StorageMove {
|
|
68
|
+
private readonly configFile;
|
|
69
|
+
private readonly busy;
|
|
70
|
+
/** Whether a sandbox runs on this PC (given by the caller: host/sandbox imports this folder). */
|
|
71
|
+
private readonly sandboxRunning;
|
|
72
|
+
private readonly protect?;
|
|
73
|
+
private readonly env;
|
|
74
|
+
/**
|
|
75
|
+
* @param configFile the user's config.json (created if needed): storage.root is pinned in it
|
|
76
|
+
* @param busy why a move cannot happen now (a background job on the old folder), or null
|
|
77
|
+
*/
|
|
78
|
+
constructor(configFile: string, busy: () => string | null,
|
|
79
|
+
/** Whether a sandbox runs on this PC (given by the caller: host/sandbox imports this folder). */
|
|
80
|
+
sandboxRunning: () => boolean, protect?: ((dir: string) => void) | undefined, env?: NodeJS.ProcessEnv);
|
|
81
|
+
/** Throws a UserError when this move is not possible right now. */
|
|
82
|
+
validate(from: string, to: string): void;
|
|
83
|
+
move(from: string, to: string, options?: MoveOptions): Promise<MoveResult>;
|
|
84
|
+
/** Writes storage.root without moving anything (sandbox storage use). */
|
|
85
|
+
pin(target: string): void;
|
|
86
|
+
/** Creates the target, private when it is under the users folder, before anything is written in it. */
|
|
87
|
+
private prepare;
|
|
88
|
+
private rename;
|
|
89
|
+
private undoRename;
|
|
90
|
+
private copy;
|
|
91
|
+
/** Failure cleanup: removes what a failed copy left, never the old folder. */
|
|
92
|
+
private discard;
|
|
93
|
+
private removeOld;
|
|
94
|
+
private removeEmpty;
|
|
95
|
+
}
|
|
@@ -0,0 +1,384 @@
|
|
|
1
|
+
// Moving the storage root (everything kept between sandboxes) to another folder: measuring, estimating, checking, and
|
|
2
|
+
// the move itself (rename on the same drive, a verified copy otherwise). The folder is pinned as storage.root in the
|
|
3
|
+
// user's config at the end, so an older version still finds it. Returns data and calls back; never prints.
|
|
4
|
+
import fs from 'node:fs';
|
|
5
|
+
import path from 'node:path';
|
|
6
|
+
import { pipeline } from 'node:stream/promises';
|
|
7
|
+
import { DEFAULTS } from '../../core/config/index.js';
|
|
8
|
+
import { freeBytesAt, GB, humanBytes } from '../../core/disk.js';
|
|
9
|
+
import { errMsg, expandPath, fail, isInsideOrEqual, isLink, isRootPath } from '../../core/util/index.js';
|
|
10
|
+
import { safeRemove } from '../../shared/io/index.js';
|
|
11
|
+
import { setValue } from '../migrate/migrations/config-file.js';
|
|
12
|
+
import { ensureStorageRoot, OLD_DEFAULT_ROOT, oldDefaultRoot } from './root.js';
|
|
13
|
+
/** A copy is estimated at this speed, plus a cost per file (small files are slower than big ones). */
|
|
14
|
+
export const COPY_BYTES_PER_SECOND = 80 * 1024 * 1024;
|
|
15
|
+
export const COPY_SECONDS_PER_FILE = 0.002;
|
|
16
|
+
/** Above these a move is called big: the dialog and the command warn. */
|
|
17
|
+
export const BIG_BYTES = 5 * GB;
|
|
18
|
+
export const BIG_FILES = 200_000;
|
|
19
|
+
/** Measuring stops after this long or this many entries and reports "at least". */
|
|
20
|
+
export const MEASURE_MS = 20_000;
|
|
21
|
+
export const MEASURE_ENTRIES = 3_000_000;
|
|
22
|
+
/** Files from this size on are copied as a stream, so progress moves while one big file copies. */
|
|
23
|
+
const STREAM_FROM_BYTES = 64 * 1024 * 1024;
|
|
24
|
+
/** Used when no way to make a folder private was given: a shared-tree target is refused rather than left open. */
|
|
25
|
+
const refuseUnprotected = (dir) => fail('Cannot make ' + dir + ' private here.', 'Move the data with sandbox storage move on your PC.');
|
|
26
|
+
/** Size and file count, never following links or junctions, with a time and entry limit. */
|
|
27
|
+
export function measureFolder(root, maxMs = MEASURE_MS, maxEntries = MEASURE_ENTRIES) {
|
|
28
|
+
const deadline = Date.now() + maxMs;
|
|
29
|
+
let bytes = 0;
|
|
30
|
+
let files = 0;
|
|
31
|
+
let entries = 0;
|
|
32
|
+
const stack = [root];
|
|
33
|
+
while (stack.length) {
|
|
34
|
+
const dir = stack.pop();
|
|
35
|
+
let list;
|
|
36
|
+
try {
|
|
37
|
+
list = fs.readdirSync(dir, { withFileTypes: true });
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
continue; // gone or unreadable: counts as nothing
|
|
41
|
+
}
|
|
42
|
+
for (const entry of list) {
|
|
43
|
+
if (++entries > maxEntries || (entries % 512 === 0 && Date.now() > deadline))
|
|
44
|
+
return { bytes, files, partial: true };
|
|
45
|
+
if (entry.isSymbolicLink())
|
|
46
|
+
continue;
|
|
47
|
+
const full = path.join(dir, entry.name);
|
|
48
|
+
if (entry.isDirectory()) {
|
|
49
|
+
stack.push(full);
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
try {
|
|
53
|
+
bytes += fs.lstatSync(full).size;
|
|
54
|
+
files++;
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
// vanished while measuring
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return { bytes, files, partial: false };
|
|
62
|
+
}
|
|
63
|
+
/** Do both folders (the target may not exist yet) sit on the same volume? */
|
|
64
|
+
export function sameVolume(from, to) {
|
|
65
|
+
const near = (p) => {
|
|
66
|
+
let at = path.resolve(p);
|
|
67
|
+
while (!fs.existsSync(at) && path.dirname(at) !== at)
|
|
68
|
+
at = path.dirname(at);
|
|
69
|
+
return at;
|
|
70
|
+
};
|
|
71
|
+
const a = near(from);
|
|
72
|
+
const b = near(to);
|
|
73
|
+
if (path.parse(a).root.toLowerCase() !== path.parse(b).root.toLowerCase())
|
|
74
|
+
return false;
|
|
75
|
+
try {
|
|
76
|
+
return fs.statSync(a).dev === fs.statSync(b).dev;
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
/** The pure part of the estimate: time, room and whether it is big. `freeBytes` null = unknown (assumed enough). */
|
|
83
|
+
export function estimateMove(measured, same, freeBytes) {
|
|
84
|
+
const seconds = same
|
|
85
|
+
? Math.max(1, Math.ceil(measured.files / 50_000))
|
|
86
|
+
: Math.ceil(measured.bytes / COPY_BYTES_PER_SECOND + measured.files * COPY_SECONDS_PER_FILE);
|
|
87
|
+
const fits = same || freeBytes === null || freeBytes > measured.bytes * 1.02 + 64 * 1024 * 1024;
|
|
88
|
+
return {
|
|
89
|
+
sameVolume: same,
|
|
90
|
+
seconds,
|
|
91
|
+
freeBytes,
|
|
92
|
+
fits,
|
|
93
|
+
big: measured.bytes > BIG_BYTES || measured.files > BIG_FILES,
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
export function estimate(from, to, measured, copyOnly = false) {
|
|
97
|
+
const same = !copyOnly && sameVolume(from, to);
|
|
98
|
+
return estimateMove(measured, same, same ? null : freeBytesAt(to));
|
|
99
|
+
}
|
|
100
|
+
/** "about 3 minutes", "a few seconds". */
|
|
101
|
+
export function describeDuration(seconds) {
|
|
102
|
+
if (seconds < 10)
|
|
103
|
+
return 'a few seconds';
|
|
104
|
+
if (seconds < 90)
|
|
105
|
+
return 'about ' + Math.round(seconds / 10) * 10 + ' seconds';
|
|
106
|
+
const minutes = Math.round(seconds / 60);
|
|
107
|
+
if (minutes < 90)
|
|
108
|
+
return 'about ' + minutes + ' minutes';
|
|
109
|
+
const hours = Math.round(seconds / 360) / 10;
|
|
110
|
+
return 'about ' + hours + ' hours';
|
|
111
|
+
}
|
|
112
|
+
/** "12.3 GB, 412,000 files", with "at least" when the measuring stopped early. */
|
|
113
|
+
export function describeSize(measured) {
|
|
114
|
+
return ((measured.partial ? 'at least ' : '') +
|
|
115
|
+
humanBytes(measured.bytes) +
|
|
116
|
+
', ' +
|
|
117
|
+
measured.files.toLocaleString('en-US') +
|
|
118
|
+
' files');
|
|
119
|
+
}
|
|
120
|
+
/** A warning line for a big or too-big move, or null. */
|
|
121
|
+
export function moveWarning(measured, est) {
|
|
122
|
+
if (!est.fits)
|
|
123
|
+
return ('The target drive has ' +
|
|
124
|
+
(est.freeBytes === null ? 'too little' : humanBytes(est.freeBytes)) +
|
|
125
|
+
' free; this needs ' +
|
|
126
|
+
humanBytes(measured.bytes) +
|
|
127
|
+
' and some room to spare.');
|
|
128
|
+
if (est.big)
|
|
129
|
+
return ('This is a lot of data (' + describeSize(measured) + '): the move takes ' + describeDuration(est.seconds) + '.');
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
132
|
+
/** What to store in config.json for this folder: the %VARIABLE% form when it is a default, else the full path. */
|
|
133
|
+
export function pinValue(folder, env = process.env) {
|
|
134
|
+
const same = (a, b) => path.resolve(a).toLowerCase() === path.resolve(b).toLowerCase();
|
|
135
|
+
const shared = expandPath(DEFAULTS.storage.root, process.cwd());
|
|
136
|
+
if (same(folder, shared))
|
|
137
|
+
return DEFAULTS.storage.root;
|
|
138
|
+
const old = oldDefaultRoot(env);
|
|
139
|
+
if (old && same(folder, old))
|
|
140
|
+
return OLD_DEFAULT_ROOT;
|
|
141
|
+
return path.resolve(folder);
|
|
142
|
+
}
|
|
143
|
+
/** Why `from` -> `to` is not allowed, or null. `allowNonEmpty`: the target may hold data already (switching to it). */
|
|
144
|
+
export function moveProblem(from, to, allowNonEmpty = false) {
|
|
145
|
+
const a = path.resolve(from);
|
|
146
|
+
const b = path.resolve(to);
|
|
147
|
+
if (!path.isAbsolute(to))
|
|
148
|
+
return { message: to + ' is not a full path.', fix: 'Give a path like D:\\Sandbox.' };
|
|
149
|
+
if (isRootPath(b))
|
|
150
|
+
return { message: b + ' is a whole drive.', fix: 'Pick a folder on it, e.g. ' + b + 'Sandbox.' };
|
|
151
|
+
if (a.toLowerCase() === b.toLowerCase())
|
|
152
|
+
return { message: 'Your data is in that folder already.', fix: '' };
|
|
153
|
+
if (isInsideOrEqual(a, b))
|
|
154
|
+
return { message: 'The new folder is inside the old one.', fix: 'Pick a folder outside ' + a + '.' };
|
|
155
|
+
if (isInsideOrEqual(b, a))
|
|
156
|
+
return { message: 'The old folder is inside the new one.', fix: 'Pick a folder that does not contain ' + a + '.' };
|
|
157
|
+
if (isLink(b) || isLink(path.dirname(b)))
|
|
158
|
+
return { message: b + ' (or the folder above it) is a link.', fix: 'Pick a plain folder.' };
|
|
159
|
+
if (fs.existsSync(b)) {
|
|
160
|
+
let entries = [];
|
|
161
|
+
try {
|
|
162
|
+
if (!fs.statSync(b).isDirectory())
|
|
163
|
+
return { message: b + ' is a file.', fix: 'Pick a folder.' };
|
|
164
|
+
entries = fs.readdirSync(b);
|
|
165
|
+
}
|
|
166
|
+
catch (e) {
|
|
167
|
+
return { message: 'Cannot look into ' + b + ': ' + errMsg(e), fix: 'Pick another folder.' };
|
|
168
|
+
}
|
|
169
|
+
if (entries.length && !allowNonEmpty)
|
|
170
|
+
return { message: b + ' is not empty.', fix: 'Pick an empty or new folder.' };
|
|
171
|
+
}
|
|
172
|
+
return null;
|
|
173
|
+
}
|
|
174
|
+
export class StorageMove {
|
|
175
|
+
configFile;
|
|
176
|
+
busy;
|
|
177
|
+
sandboxRunning;
|
|
178
|
+
protect;
|
|
179
|
+
env;
|
|
180
|
+
/**
|
|
181
|
+
* @param configFile the user's config.json (created if needed): storage.root is pinned in it
|
|
182
|
+
* @param busy why a move cannot happen now (a background job on the old folder), or null
|
|
183
|
+
*/
|
|
184
|
+
constructor(configFile, busy,
|
|
185
|
+
/** Whether a sandbox runs on this PC (given by the caller: host/sandbox imports this folder). */
|
|
186
|
+
sandboxRunning, protect, env = process.env) {
|
|
187
|
+
this.configFile = configFile;
|
|
188
|
+
this.busy = busy;
|
|
189
|
+
this.sandboxRunning = sandboxRunning;
|
|
190
|
+
this.protect = protect;
|
|
191
|
+
this.env = env;
|
|
192
|
+
}
|
|
193
|
+
/** Throws a UserError when this move is not possible right now. */
|
|
194
|
+
validate(from, to) {
|
|
195
|
+
if (!fs.existsSync(from) || !fs.statSync(from).isDirectory())
|
|
196
|
+
fail('There is no folder to move: ' + from + ' does not exist.');
|
|
197
|
+
if (isLink(from))
|
|
198
|
+
fail(from + ' is a link.', 'Move the real folder, not a link.');
|
|
199
|
+
const problem = moveProblem(from, to);
|
|
200
|
+
if (problem)
|
|
201
|
+
fail(problem.message, problem.fix || undefined);
|
|
202
|
+
if (this.sandboxRunning())
|
|
203
|
+
fail('A Windows Sandbox is running.', 'Close it (sandbox stop), then move your data.');
|
|
204
|
+
const why = this.busy();
|
|
205
|
+
if (why)
|
|
206
|
+
fail(why, 'Wait a minute, then try again.');
|
|
207
|
+
}
|
|
208
|
+
async move(from, to, options = {}) {
|
|
209
|
+
this.validate(from, to);
|
|
210
|
+
const target = path.resolve(to);
|
|
211
|
+
const source = path.resolve(from);
|
|
212
|
+
const measured = measureFolder(source);
|
|
213
|
+
const est = estimate(source, target, measured, Boolean(options.forceCopy || options.keepOld));
|
|
214
|
+
if (!est.fits)
|
|
215
|
+
fail(moveWarning(measured, est) ?? 'Not enough room.', 'Free some space or pick another drive.');
|
|
216
|
+
const existedBefore = fs.existsSync(target);
|
|
217
|
+
const notes = [];
|
|
218
|
+
let copiedFiles = measured.files;
|
|
219
|
+
let copiedBytes = measured.bytes;
|
|
220
|
+
let skippedLinks = 0;
|
|
221
|
+
let renamed = false;
|
|
222
|
+
try {
|
|
223
|
+
this.prepare(target);
|
|
224
|
+
if (est.sameVolume) {
|
|
225
|
+
this.rename(source, target);
|
|
226
|
+
renamed = true;
|
|
227
|
+
}
|
|
228
|
+
else {
|
|
229
|
+
const done = await this.copy(source, target, options.onProgress);
|
|
230
|
+
copiedFiles = done.files;
|
|
231
|
+
copiedBytes = done.bytes;
|
|
232
|
+
skippedLinks = done.links;
|
|
233
|
+
}
|
|
234
|
+
this.pin(target);
|
|
235
|
+
}
|
|
236
|
+
catch (e) {
|
|
237
|
+
// Back to how it was: the old folder is whole again, the config is untouched, what was made in the target goes.
|
|
238
|
+
if (renamed)
|
|
239
|
+
this.undoRename(source, target);
|
|
240
|
+
this.discard(target, existedBefore);
|
|
241
|
+
throw e;
|
|
242
|
+
}
|
|
243
|
+
let removedOld = false;
|
|
244
|
+
if (est.sameVolume)
|
|
245
|
+
removedOld = this.removeEmpty(source, notes);
|
|
246
|
+
else if (options.keepOld)
|
|
247
|
+
notes.push('The old folder is kept: ' + source);
|
|
248
|
+
else if (skippedLinks)
|
|
249
|
+
notes.push('The old folder is kept because it holds ' + skippedLinks + ' link(s): ' + source);
|
|
250
|
+
else
|
|
251
|
+
removedOld = this.removeOld(source, notes);
|
|
252
|
+
return {
|
|
253
|
+
from: source,
|
|
254
|
+
to: target,
|
|
255
|
+
copied: !est.sameVolume,
|
|
256
|
+
files: copiedFiles,
|
|
257
|
+
bytes: copiedBytes,
|
|
258
|
+
pinned: pinValue(target, this.env),
|
|
259
|
+
removedOld,
|
|
260
|
+
notes,
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
/** Writes storage.root without moving anything (sandbox storage use). */
|
|
264
|
+
pin(target) {
|
|
265
|
+
setValue(this.configFile, ['storage', 'root'], pinValue(target, this.env));
|
|
266
|
+
}
|
|
267
|
+
/** Creates the target, private when it is under the users folder, before anything is written in it. */
|
|
268
|
+
prepare(target) {
|
|
269
|
+
ensureStorageRoot(target, this.protect ?? refuseUnprotected, this.env);
|
|
270
|
+
}
|
|
271
|
+
rename(source, target) {
|
|
272
|
+
const moved = [];
|
|
273
|
+
try {
|
|
274
|
+
for (const name of fs.readdirSync(source)) {
|
|
275
|
+
fs.renameSync(path.join(source, name), path.join(target, name));
|
|
276
|
+
moved.push(name);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
catch (e) {
|
|
280
|
+
for (const name of moved.reverse()) {
|
|
281
|
+
try {
|
|
282
|
+
fs.renameSync(path.join(target, name), path.join(source, name));
|
|
283
|
+
}
|
|
284
|
+
catch {
|
|
285
|
+
// best effort: the message below says where the rest is
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
fail('Moving stopped: ' + errMsg(e), 'Nothing was changed. Close programs that use ' + source + ' and try again.');
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
undoRename(source, target) {
|
|
292
|
+
for (const name of fs.readdirSync(target)) {
|
|
293
|
+
try {
|
|
294
|
+
fs.renameSync(path.join(target, name), path.join(source, name));
|
|
295
|
+
}
|
|
296
|
+
catch {
|
|
297
|
+
// best effort
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
async copy(source, target, onProgress) {
|
|
302
|
+
const done = { bytes: 0, files: 0, links: 0 };
|
|
303
|
+
let lastReport = 0;
|
|
304
|
+
const report = (force = false) => {
|
|
305
|
+
if (!onProgress || (!force && Date.now() - lastReport < 200))
|
|
306
|
+
return;
|
|
307
|
+
lastReport = Date.now();
|
|
308
|
+
onProgress({ bytes: done.bytes, files: done.files });
|
|
309
|
+
};
|
|
310
|
+
const walk = async (from, to) => {
|
|
311
|
+
await fs.promises.mkdir(to, { recursive: true });
|
|
312
|
+
for (const entry of await fs.promises.readdir(from, { withFileTypes: true })) {
|
|
313
|
+
const a = path.join(from, entry.name);
|
|
314
|
+
const b = path.join(to, entry.name);
|
|
315
|
+
if (entry.isSymbolicLink()) {
|
|
316
|
+
done.links++;
|
|
317
|
+
continue;
|
|
318
|
+
}
|
|
319
|
+
if (entry.isDirectory()) {
|
|
320
|
+
await walk(a, b);
|
|
321
|
+
continue;
|
|
322
|
+
}
|
|
323
|
+
const stat = await fs.promises.stat(a);
|
|
324
|
+
if (stat.size >= STREAM_FROM_BYTES) {
|
|
325
|
+
const before = done.bytes;
|
|
326
|
+
const input = fs.createReadStream(a);
|
|
327
|
+
input.on('data', () => {
|
|
328
|
+
done.bytes = before + input.bytesRead;
|
|
329
|
+
report();
|
|
330
|
+
});
|
|
331
|
+
await pipeline(input, fs.createWriteStream(b));
|
|
332
|
+
done.bytes = before;
|
|
333
|
+
}
|
|
334
|
+
else
|
|
335
|
+
await fs.promises.copyFile(a, b);
|
|
336
|
+
const copied = await fs.promises.stat(b);
|
|
337
|
+
if (copied.size !== stat.size)
|
|
338
|
+
fail('The copy of ' + a + ' has another size than the original.');
|
|
339
|
+
await fs.promises.utimes(b, stat.atime, stat.mtime);
|
|
340
|
+
done.bytes += stat.size;
|
|
341
|
+
done.files++;
|
|
342
|
+
report();
|
|
343
|
+
}
|
|
344
|
+
};
|
|
345
|
+
await walk(source, target);
|
|
346
|
+
report(true);
|
|
347
|
+
return done;
|
|
348
|
+
}
|
|
349
|
+
/** Failure cleanup: removes what a failed copy left, never the old folder. */
|
|
350
|
+
discard(target, existedBefore) {
|
|
351
|
+
try {
|
|
352
|
+
if (!existedBefore)
|
|
353
|
+
safeRemove(target, path.dirname(target));
|
|
354
|
+
else
|
|
355
|
+
for (const name of fs.readdirSync(target))
|
|
356
|
+
safeRemove(path.join(target, name), target);
|
|
357
|
+
}
|
|
358
|
+
catch {
|
|
359
|
+
// the original error is the one to show; a leftover partial folder is only wasted space
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
removeOld(source, notes) {
|
|
363
|
+
try {
|
|
364
|
+
safeRemove(source, path.dirname(source));
|
|
365
|
+
if (!fs.existsSync(source))
|
|
366
|
+
return true;
|
|
367
|
+
notes.push('Some of the old folder could not be removed: ' + source);
|
|
368
|
+
}
|
|
369
|
+
catch (e) {
|
|
370
|
+
notes.push('The old folder could not be removed (' + errMsg(e) + '): ' + source);
|
|
371
|
+
}
|
|
372
|
+
return false;
|
|
373
|
+
}
|
|
374
|
+
removeEmpty(source, notes) {
|
|
375
|
+
try {
|
|
376
|
+
fs.rmdirSync(source);
|
|
377
|
+
return true;
|
|
378
|
+
}
|
|
379
|
+
catch (e) {
|
|
380
|
+
notes.push('The old folder is still there (' + errMsg(e) + '): ' + source);
|
|
381
|
+
return false;
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { StorageHistory } from './history.js';
|
|
2
|
+
export interface MoveOffer {
|
|
3
|
+
readonly from: string;
|
|
4
|
+
readonly to: string;
|
|
5
|
+
/** `to` is the shared default folder (the wording says "the default folder"). */
|
|
6
|
+
readonly toIsDefault: boolean;
|
|
7
|
+
}
|
|
8
|
+
/** Folders that may hold saved data, other than `current`: the old default, the shared default, the remembered ones. */
|
|
9
|
+
export declare function otherDataFolders(current: string, history: StorageHistory, env?: NodeJS.ProcessEnv): string[];
|
|
10
|
+
/** What to offer, or null (nothing to move, the user said no, or the move would not be allowed anyway). */
|
|
11
|
+
export declare function planOffer(current: string, history: StorageHistory, env?: NodeJS.ProcessEnv): MoveOffer | null;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// When to offer moving the saved data: after an upgrade (it is in the old per-user folder, the default is a new one),
|
|
2
|
+
// after switching the install type, or after a downgrade and upgrade (the configured folder is empty while an earlier
|
|
3
|
+
// one holds the data). Pure apart from looking at the folders.
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import { moveProblem } from './move.js';
|
|
6
|
+
import { holdsData, oldDefaultRoot, sharedDefaultRoot } from './root.js';
|
|
7
|
+
const same = (a, b) => path.resolve(a).toLowerCase() === path.resolve(b).toLowerCase();
|
|
8
|
+
/** Folders that may hold saved data, other than `current`: the old default, the shared default, the remembered ones. */
|
|
9
|
+
export function otherDataFolders(current, history, env = process.env) {
|
|
10
|
+
const old = oldDefaultRoot(env);
|
|
11
|
+
const candidates = [old, sharedDefaultRoot(), ...history.read().previous].filter((p) => Boolean(p));
|
|
12
|
+
const unique = candidates.filter((p, i) => candidates.findIndex((q) => same(p, q)) === i);
|
|
13
|
+
return unique.filter((p) => !same(p, current) && holdsData(p));
|
|
14
|
+
}
|
|
15
|
+
/** What to offer, or null (nothing to move, the user said no, or the move would not be allowed anyway). */
|
|
16
|
+
export function planOffer(current, history, env = process.env) {
|
|
17
|
+
if (!history.mayAsk())
|
|
18
|
+
return null;
|
|
19
|
+
const shared = sharedDefaultRoot();
|
|
20
|
+
const old = oldDefaultRoot(env);
|
|
21
|
+
let offer = null;
|
|
22
|
+
if (holdsData(current)) {
|
|
23
|
+
// Still in the old per-user folder (pinned by the upgrade): the new default is where it should go. A folder
|
|
24
|
+
// chosen on purpose is never asked about.
|
|
25
|
+
if (old && same(current, old) && !same(shared, current) && !holdsData(shared))
|
|
26
|
+
offer = { from: current, to: shared, toIsDefault: true };
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
const from = otherDataFolders(current, history, env)[0];
|
|
30
|
+
if (from)
|
|
31
|
+
offer = { from, to: current, toIsDefault: same(current, shared) };
|
|
32
|
+
}
|
|
33
|
+
if (!offer || moveProblem(offer.from, offer.to))
|
|
34
|
+
return null;
|
|
35
|
+
return offer;
|
|
36
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type ContainedDeps, type HolderId } from '../contained/contained-storage.js';
|
|
2
|
+
import type { DataSet, PreparedStorage, ProviderCheck, StorageProvider } from './types.js';
|
|
3
|
+
export declare class ContainedStorageProvider implements StorageProvider {
|
|
4
|
+
private readonly deps;
|
|
5
|
+
private readonly holder;
|
|
6
|
+
private readonly availability;
|
|
7
|
+
readonly id = "vhdx-mounted";
|
|
8
|
+
private storage;
|
|
9
|
+
constructor(deps: ContainedDeps, holder?: HolderId, availability?: () => ProviderCheck);
|
|
10
|
+
check(): Promise<ProviderCheck>;
|
|
11
|
+
/** Mounts the image (the one Windows permission prompt of a launch, when it is not mounted yet). */
|
|
12
|
+
prepare(dataSet: DataSet): Promise<PreparedStorage>;
|
|
13
|
+
/** Lets go of the mount (a launch that stopped before the sandbox started). The watcher holds it afterwards. */
|
|
14
|
+
release(): Promise<void>;
|
|
15
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// Contained storage for the Windows Sandbox engine (beta, untested on a real PC): the data set splits. `run\` stays
|
|
2
|
+
// the plain data folder shared in as before; tools, state, logs, databases and cache live in a disk image that is
|
|
3
|
+
// mounted at <storage>\mounts\<set> (no drive letter) and shared in from there, to the same guest paths.
|
|
4
|
+
import fs from 'node:fs';
|
|
5
|
+
import path from 'node:path';
|
|
6
|
+
import { containedAvailability } from '../contained/check.js';
|
|
7
|
+
import { ContainedStorage } from '../contained/contained-storage.js';
|
|
8
|
+
import { containedMappings, setNameOf } from '../contained/layout.js';
|
|
9
|
+
export class ContainedStorageProvider {
|
|
10
|
+
deps;
|
|
11
|
+
holder;
|
|
12
|
+
availability;
|
|
13
|
+
id = 'vhdx-mounted';
|
|
14
|
+
storage = null;
|
|
15
|
+
constructor(deps, holder = { id: 'launch', pid: process.pid }, availability = containedAvailability) {
|
|
16
|
+
this.deps = deps;
|
|
17
|
+
this.holder = holder;
|
|
18
|
+
this.availability = availability;
|
|
19
|
+
}
|
|
20
|
+
check() {
|
|
21
|
+
return Promise.resolve(this.availability());
|
|
22
|
+
}
|
|
23
|
+
/** Mounts the image (the one Windows permission prompt of a launch, when it is not mounted yet). */
|
|
24
|
+
async prepare(dataSet) {
|
|
25
|
+
const storage = new ContainedStorage(this.deps, setNameOf(dataSet.dataPath));
|
|
26
|
+
this.storage = storage;
|
|
27
|
+
const mount = await storage.acquire(this.holder);
|
|
28
|
+
fs.mkdirSync(path.join(dataSet.dataPath, 'run'), { recursive: true });
|
|
29
|
+
const mappings = containedMappings(dataSet.dataPath, mount, dataSet.guest);
|
|
30
|
+
return {
|
|
31
|
+
attachments: mappings.map((m) => ({ kind: 'folder', host: m.host, guest: m.guest, readOnly: m.readOnly })),
|
|
32
|
+
mappings,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
/** Lets go of the mount (a launch that stopped before the sandbox started). The watcher holds it afterwards. */
|
|
36
|
+
async release() {
|
|
37
|
+
await this.storage?.release(this.holder.id);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { ResolvedMapping } from '../../../core/types.js';
|
|
2
|
+
import type { DataSet, PreparedStorage, ProviderCheck, StorageAttachment, StorageProvider } from './types.js';
|
|
3
|
+
/** The data folder as a read/write attachment. */
|
|
4
|
+
export declare function folderAttachment(dataSet: DataSet): StorageAttachment;
|
|
5
|
+
/** The data folder as a mapping (the launch builds its mapping list synchronously, so this is the plain function). */
|
|
6
|
+
export declare function dataMapping(dataSet: DataSet): ResolvedMapping;
|
|
7
|
+
export declare class FolderStorageProvider implements StorageProvider {
|
|
8
|
+
readonly id = "folder";
|
|
9
|
+
check(): Promise<ProviderCheck>;
|
|
10
|
+
prepare(dataSet: DataSet): Promise<PreparedStorage>;
|
|
11
|
+
release(): Promise<void>;
|
|
12
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/** The data folder as a read/write attachment. */
|
|
2
|
+
export function folderAttachment(dataSet) {
|
|
3
|
+
return { kind: 'folder', host: dataSet.dataPath, guest: dataSet.guest, readOnly: false };
|
|
4
|
+
}
|
|
5
|
+
/** The data folder as a mapping (the launch builds its mapping list synchronously, so this is the plain function). */
|
|
6
|
+
export function dataMapping(dataSet) {
|
|
7
|
+
return { host: dataSet.dataPath, guest: dataSet.guest, readOnly: false };
|
|
8
|
+
}
|
|
9
|
+
export class FolderStorageProvider {
|
|
10
|
+
id = 'folder';
|
|
11
|
+
check() {
|
|
12
|
+
return Promise.resolve({ available: true, reasons: [], fixes: [] });
|
|
13
|
+
}
|
|
14
|
+
prepare(dataSet) {
|
|
15
|
+
return Promise.resolve({ attachments: [folderAttachment(dataSet)], mappings: [dataMapping(dataSet)] });
|
|
16
|
+
}
|
|
17
|
+
release() {
|
|
18
|
+
return Promise.resolve();
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { FolderStorageProvider, dataMapping, folderAttachment } from './folder.js';
|
|
2
|
+
export { ContainedStorageProvider } from './contained.js';
|
|
3
|
+
export { providerFor, type ProviderOptions } from './registry.js';
|
|
4
|
+
export type { DataSet, PreparedStorage, ProviderCheck, StorageAttachment, StorageProvider } from './types.js';
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Config } from '../../../core/types.js';
|
|
2
|
+
import type { ContainedDeps } from '../contained/contained-storage.js';
|
|
3
|
+
import type { ProviderCheck, StorageProvider } from './types.js';
|
|
4
|
+
export interface ProviderOptions {
|
|
5
|
+
readonly contained?: ContainedDeps;
|
|
6
|
+
/** Tests: the answer of the availability check. */
|
|
7
|
+
readonly availability?: () => ProviderCheck;
|
|
8
|
+
}
|
|
9
|
+
export declare function providerFor(config: Config, options?: ProviderOptions): StorageProvider;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { fail } from '../../../core/util/index.js';
|
|
2
|
+
import { containedAvailability } from '../contained/check.js';
|
|
3
|
+
import { FolderStorageProvider } from './folder.js';
|
|
4
|
+
import { ContainedStorageProvider } from './contained.js';
|
|
5
|
+
export function providerFor(config, options = {}) {
|
|
6
|
+
if (config.storage.contained === 'off')
|
|
7
|
+
return new FolderStorageProvider();
|
|
8
|
+
const check = (options.availability ?? containedAvailability)();
|
|
9
|
+
if (!check.available)
|
|
10
|
+
fail('Contained storage cannot be used: ' + check.reasons.join(' '), check.fixes.join(' ') || 'Set storage.contained to "off" (the default) in your settings.');
|
|
11
|
+
if (!options.contained)
|
|
12
|
+
fail('Contained storage was not set up for this command.', 'Set storage.contained to "off" and report this.');
|
|
13
|
+
return new ContainedStorageProvider(options.contained, undefined, options.availability);
|
|
14
|
+
}
|