windows-development-sandbox 1.4.0 → 1.4.3
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/.sandbox-config.example.json +2 -1
- package/config.example.json +4 -1
- package/dist/api.js +27 -16
- package/dist/cli/args.d.ts +4 -6
- package/dist/cli/args.js +67 -34
- package/dist/cli/argv.d.ts +9 -0
- package/dist/cli/argv.js +22 -0
- package/dist/cli/commands/accounts.d.ts +1 -1
- package/dist/cli/commands/accounts.js +42 -27
- package/dist/cli/commands/agent-commands.d.ts +3 -3
- package/dist/cli/commands/agent-commands.js +27 -18
- package/dist/cli/commands/context.d.ts +9 -11
- package/dist/cli/commands/context.js +35 -32
- package/dist/cli/commands/data/clean.d.ts +2 -2
- package/dist/cli/commands/data/clean.js +27 -11
- package/dist/cli/commands/data/collect.d.ts +6 -3
- package/dist/cli/commands/data/collect.js +46 -15
- package/dist/cli/commands/data/index.d.ts +2 -2
- package/dist/cli/commands/data/index.js +30 -12
- package/dist/cli/commands/data/remove.d.ts +1 -1
- package/dist/cli/commands/data/remove.js +4 -4
- package/dist/cli/commands/index.d.ts +5 -4
- package/dist/cli/commands/index.js +5 -4
- package/dist/cli/commands/launch/add-root.d.ts +7 -0
- package/dist/cli/commands/launch/add-root.js +64 -0
- package/dist/cli/commands/launch/boot-progress.d.ts +7 -0
- package/dist/cli/commands/launch/boot-progress.js +48 -0
- package/dist/cli/commands/launch/boot-wants.d.ts +11 -0
- package/dist/cli/commands/launch/boot-wants.js +48 -0
- package/dist/cli/commands/launch/first-start.d.ts +10 -0
- package/dist/cli/commands/launch/first-start.js +53 -0
- package/dist/cli/commands/launch/index.d.ts +6 -0
- package/dist/cli/commands/launch/index.js +6 -0
- package/dist/cli/commands/launch/launch.d.ts +8 -0
- package/dist/cli/commands/launch/launch.js +211 -0
- package/dist/cli/commands/launch/prepare.d.ts +23 -0
- package/dist/cli/commands/launch/prepare.js +109 -0
- package/dist/cli/commands/launch/running.d.ts +45 -0
- package/dist/cli/commands/launch/running.js +218 -0
- package/dist/cli/commands/launch/summary.d.ts +8 -0
- package/dist/cli/commands/launch/summary.js +98 -0
- package/dist/cli/commands/maintenance/audit.d.ts +3 -0
- package/dist/cli/commands/maintenance/audit.js +58 -0
- package/dist/cli/commands/maintenance/clean.d.ts +2 -0
- package/dist/cli/commands/maintenance/clean.js +10 -0
- package/dist/cli/commands/maintenance/config.d.ts +2 -0
- package/dist/cli/commands/maintenance/config.js +145 -0
- package/dist/cli/commands/maintenance/doctor.d.ts +2 -0
- package/dist/cli/commands/maintenance/doctor.js +52 -0
- package/dist/cli/commands/maintenance/host-claude.d.ts +2 -0
- package/dist/cli/commands/maintenance/host-claude.js +4 -0
- package/dist/cli/commands/maintenance/index.d.ts +8 -0
- package/dist/cli/commands/maintenance/index.js +9 -0
- package/dist/cli/commands/maintenance/logs.d.ts +2 -0
- package/dist/cli/commands/maintenance/logs.js +44 -0
- package/dist/cli/commands/maintenance/sync.d.ts +2 -0
- package/dist/cli/commands/maintenance/sync.js +12 -0
- package/dist/cli/commands/maintenance/watch.d.ts +3 -0
- package/dist/cli/commands/maintenance/watch.js +6 -0
- package/dist/cli/commands/projects/describe-sessions.d.ts +3 -0
- package/dist/cli/commands/projects/describe-sessions.js +15 -0
- package/dist/cli/commands/projects/here.d.ts +38 -0
- package/dist/cli/commands/projects/here.js +145 -0
- package/dist/cli/commands/projects/index.d.ts +4 -0
- package/dist/cli/commands/projects/index.js +4 -0
- package/dist/cli/commands/projects/projects.d.ts +14 -0
- package/dist/cli/commands/projects/projects.js +213 -0
- package/dist/cli/commands/projects/restart.d.ts +15 -0
- package/dist/cli/commands/projects/restart.js +149 -0
- package/dist/cli/commands/registry.d.ts +3 -0
- package/dist/cli/commands/registry.js +34 -0
- package/dist/cli/commands/repair/checks.js +105 -29
- package/dist/cli/commands/repair/finders.d.ts +13 -10
- package/dist/cli/commands/repair/finders.js +63 -43
- package/dist/cli/commands/repair/index.d.ts +4 -4
- package/dist/cli/commands/repair/index.js +47 -21
- package/dist/cli/commands/repair/types.d.ts +2 -2
- package/dist/cli/commands/repair/types.js +7 -2
- package/dist/cli/commands/sessions/attach.d.ts +2 -0
- package/dist/cli/commands/sessions/attach.js +45 -0
- package/dist/cli/commands/sessions/control.d.ts +4 -0
- package/dist/cli/commands/sessions/control.js +62 -0
- package/dist/cli/commands/sessions/exec.d.ts +6 -0
- package/dist/cli/commands/sessions/exec.js +72 -0
- package/dist/cli/commands/sessions/index.d.ts +6 -0
- package/dist/cli/commands/sessions/index.js +9 -0
- package/dist/cli/commands/sessions/list.d.ts +15 -0
- package/dist/cli/commands/sessions/list.js +65 -0
- package/dist/cli/commands/sessions/status.d.ts +2 -0
- package/dist/cli/commands/sessions/status.js +153 -0
- package/dist/cli/commands/sessions/window.d.ts +3 -0
- package/dist/cli/commands/sessions/window.js +18 -0
- package/dist/cli/commands/setup/checks.d.ts +4 -4
- package/dist/cli/commands/setup/checks.js +36 -19
- package/dist/cli/commands/setup/facts.d.ts +6 -6
- package/dist/cli/commands/setup/facts.js +23 -11
- package/dist/cli/commands/setup/index.d.ts +1 -1
- package/dist/cli/commands/setup/index.js +25 -12
- package/dist/cli/commands/user-config.d.ts +5 -5
- package/dist/cli/commands/user-config.js +14 -12
- package/dist/cli/history.d.ts +5 -4
- package/dist/cli/history.js +23 -11
- package/dist/cli/index.d.ts +4 -14
- package/dist/cli/index.js +27 -77
- package/dist/cli/manifest.d.ts +464 -10
- package/dist/cli/manifest.js +328 -54
- package/dist/cli/menu/apps.d.ts +7 -5
- package/dist/cli/menu/apps.js +64 -16
- package/dist/cli/menu/command-fields.d.ts +15 -0
- package/dist/cli/menu/command-fields.js +23 -0
- package/dist/cli/menu/command-form.d.ts +3 -5
- package/dist/cli/menu/command-form.js +116 -48
- package/dist/cli/menu/home.d.ts +22 -0
- package/dist/cli/menu/home.js +72 -0
- package/dist/cli/menu/index.d.ts +2 -24
- package/dist/cli/menu/index.js +4 -178
- package/dist/cli/menu/menu.d.ts +23 -0
- package/dist/cli/menu/menu.js +185 -0
- package/dist/cli/menu/settings/categories.d.ts +2 -2
- package/dist/cli/menu/settings/categories.js +123 -20
- package/dist/cli/menu/settings/collections/collection-editor.d.ts +23 -0
- package/dist/cli/menu/settings/collections/collection-editor.js +89 -0
- package/dist/cli/menu/settings/collections/map-editor.d.ts +10 -0
- package/dist/cli/menu/settings/collections/map-editor.js +34 -0
- package/dist/cli/menu/settings/collections/object-list-editor.d.ts +10 -0
- package/dist/cli/menu/settings/collections/object-list-editor.js +23 -0
- package/dist/cli/menu/settings/collections/object-map-editor.d.ts +10 -0
- package/dist/cli/menu/settings/collections/object-map-editor.js +35 -0
- package/dist/cli/menu/settings/collections/string-list-editor.d.ts +12 -0
- package/dist/cli/menu/settings/collections/string-list-editor.js +39 -0
- package/dist/cli/menu/settings/config-file.d.ts +2 -2
- package/dist/cli/menu/settings/config-file.js +42 -19
- package/dist/cli/menu/settings/editor-actions.d.ts +2 -0
- package/dist/cli/menu/settings/editor-actions.js +2 -0
- package/dist/cli/menu/settings/format.d.ts +5 -0
- package/dist/cli/menu/settings/format.js +39 -0
- package/dist/cli/menu/settings/index.d.ts +1 -29
- package/dist/cli/menu/settings/index.js +1 -133
- package/dist/cli/menu/settings/object-editor.d.ts +12 -0
- package/dist/cli/menu/settings/object-editor.js +86 -0
- package/dist/cli/menu/settings/schema-node.d.ts +3 -1
- package/dist/cli/menu/settings/schema-node.js +71 -24
- package/dist/cli/menu/settings/settings-editor.d.ts +30 -0
- package/dist/cli/menu/settings/settings-editor.js +176 -0
- package/dist/cli/menu/settings/{editors.d.ts → value-editor.d.ts} +2 -13
- package/dist/cli/menu/settings/value-editor.js +137 -0
- package/dist/cli/menu/several.d.ts +4 -4
- package/dist/cli/menu/several.js +61 -20
- package/dist/cli/{colors.d.ts → output/colors.d.ts} +8 -8
- package/dist/cli/{colors.js → output/colors.js} +32 -14
- package/dist/cli/output/index.d.ts +3 -0
- package/dist/cli/output/index.js +3 -0
- package/dist/cli/output/print.d.ts +5 -0
- package/dist/cli/output/print.js +14 -0
- package/dist/cli/output/progress.d.ts +24 -0
- package/dist/cli/output/progress.js +124 -0
- package/dist/cli/report.d.ts +2 -0
- package/dist/cli/report.js +20 -0
- package/dist/cli/tui/app.d.ts +6 -16
- package/dist/cli/tui/app.js +28 -8
- package/dist/cli/tui/dialogs/confirm-screen.d.ts +20 -0
- package/dist/cli/tui/dialogs/confirm-screen.js +50 -0
- package/dist/cli/tui/dialogs/message-screen.d.ts +17 -0
- package/dist/cli/tui/dialogs/message-screen.js +55 -0
- package/dist/cli/tui/dialogs/paragraphs.d.ts +2 -0
- package/dist/cli/tui/dialogs/paragraphs.js +5 -0
- package/dist/cli/tui/dialogs/text-screen.d.ts +26 -0
- package/dist/cli/tui/dialogs/text-screen.js +107 -0
- package/dist/cli/tui/frame.js +3 -1
- package/dist/cli/tui/index.d.ts +7 -3
- package/dist/cli/tui/index.js +4 -2
- package/dist/cli/tui/list/list-screen.d.ts +29 -0
- package/dist/cli/tui/{list-screen.js → list/list-screen.js} +86 -23
- package/dist/cli/tui/{list-screen.d.ts → list/list-types.d.ts} +0 -28
- package/dist/cli/tui/screen.d.ts +14 -0
- package/dist/cli/tui/terminal.js +34 -10
- package/dist/cli/tui/text.d.ts +2 -1
- package/dist/cli/tui/text.js +37 -7
- package/dist/cli/tui/theme.js +27 -9
- package/dist/cli/validate.d.ts +8 -8
- package/dist/cli/validate.js +32 -21
- package/dist/core/config/defaults.d.ts +2 -0
- package/dist/core/config/defaults.js +203 -0
- package/dist/core/config/index.d.ts +2 -0
- package/dist/core/config/index.js +3 -0
- package/dist/core/{config.d.ts → config/loader.d.ts} +1 -2
- package/dist/core/config/loader.js +47 -0
- package/dist/core/{detect-databases.js → detect/databases.js} +111 -23
- package/dist/core/detect/index.d.ts +4 -0
- package/dist/core/detect/index.js +4 -0
- package/dist/core/{detect-pwsh.d.ts → detect/pwsh.d.ts} +1 -1
- package/dist/core/{detect-pwsh.js → detect/pwsh.js} +25 -11
- package/dist/core/{detect-toolchains.d.ts → detect/toolchains.d.ts} +1 -1
- package/dist/core/{detect-toolchains.js → detect/toolchains.js} +42 -5
- package/dist/{guest/toolchains → core/detect}/versions.js +28 -12
- package/dist/core/disk.d.ts +2 -0
- package/dist/core/disk.js +46 -3
- package/dist/core/local-config/boot-wants.d.ts +45 -0
- package/dist/core/local-config/boot-wants.js +120 -0
- package/dist/core/local-config/file.d.ts +3 -0
- package/dist/core/local-config/file.js +16 -0
- package/dist/core/local-config/index.d.ts +5 -0
- package/dist/core/local-config/index.js +7 -0
- package/dist/core/{local-config.d.ts → local-config/overrides.d.ts} +11 -11
- package/dist/core/{local-config.js → local-config/overrides.js} +53 -54
- package/dist/core/{project-policy.d.ts → local-config/policy.d.ts} +7 -3
- package/dist/core/{project-policy.js → local-config/policy.js} +16 -6
- package/dist/core/local-config/trust.d.ts +13 -0
- package/dist/core/local-config/trust.js +43 -0
- package/dist/core/package-info.d.ts +4 -0
- package/dist/core/package-info.js +13 -0
- package/dist/core/run/guest-workspace.d.ts +23 -0
- package/dist/core/run/guest-workspace.js +47 -0
- package/dist/core/run/index.d.ts +3 -0
- package/dist/core/run/index.js +3 -0
- package/dist/core/run/resolve-run.d.ts +3 -0
- package/dist/core/run/resolve-run.js +202 -0
- package/dist/core/run/versions.d.ts +13 -0
- package/dist/core/run/versions.js +65 -0
- package/dist/core/safe-paths.js +17 -5
- package/dist/core/schema/apps.d.ts +4 -4
- package/dist/core/schema/apps.js +55 -21
- package/dist/core/schema/common.d.ts +13 -10
- package/dist/core/schema/common.js +16 -10
- package/dist/core/schema/config.d.ts +18 -12
- package/dist/core/schema/config.js +78 -53
- package/dist/core/schema/databases.d.ts +4 -3
- package/dist/core/schema/databases.js +16 -12
- package/dist/core/schema/harness.d.ts +1 -1
- package/dist/core/schema/harness.js +17 -7
- package/dist/core/schema/index.d.ts +6 -0
- package/dist/core/schema/index.js +8 -0
- package/dist/core/schema/json-schema.js +10 -5
- package/dist/core/schema/profile.d.ts +4 -4
- package/dist/core/schema/profile.js +37 -17
- package/dist/core/schema/projects.d.ts +2 -1
- package/dist/core/schema/projects.js +16 -5
- package/dist/core/schema/sandbox.d.ts +12 -12
- package/dist/core/schema/sandbox.js +101 -37
- package/dist/core/schema/toolchains.d.ts +6 -1
- package/dist/core/schema/toolchains.js +84 -34
- package/dist/core/types.d.ts +36 -9
- package/dist/core/util/errors.d.ts +8 -0
- package/dist/core/util/errors.js +14 -0
- package/dist/core/util/fs.d.ts +8 -0
- package/dist/core/util/fs.js +40 -0
- package/dist/core/util/index.d.ts +7 -0
- package/dist/core/util/index.js +7 -0
- package/dist/core/util/jsonc.d.ts +6 -0
- package/dist/core/util/jsonc.js +25 -0
- package/dist/core/util/links.d.ts +10 -0
- package/dist/core/util/links.js +39 -0
- package/dist/core/util/paths.d.ts +7 -0
- package/dist/core/util/paths.js +33 -0
- package/dist/core/util/process.d.ts +15 -0
- package/dist/core/util/process.js +54 -0
- package/dist/core/util/text.d.ts +8 -0
- package/dist/core/util/text.js +8 -0
- package/dist/guest/{setup/agents.js → agents/agent-installer.js} +24 -4
- package/dist/guest/apps/after-install.d.ts +3 -0
- package/dist/guest/apps/after-install.js +47 -0
- package/dist/guest/apps/app-installer.d.ts +22 -0
- package/dist/guest/apps/app-installer.js +116 -0
- package/dist/guest/apps/find-exe.d.ts +5 -0
- package/dist/guest/apps/find-exe.js +41 -0
- package/dist/guest/apps/index.d.ts +3 -10
- package/dist/guest/apps/index.js +6 -206
- package/dist/guest/apps/resolvers.js +37 -9
- package/dist/guest/apps/shortcuts.d.ts +6 -0
- package/dist/guest/apps/shortcuts.js +28 -0
- package/dist/guest/apps/sources.d.ts +4 -0
- package/dist/guest/apps/sources.js +17 -0
- package/dist/guest/apps/unpack.d.ts +3 -0
- package/dist/guest/apps/unpack.js +47 -0
- package/dist/guest/{audit-parse.js → audit/parse.js} +39 -3
- package/dist/guest/{audit.d.ts → audit/process-audit.d.ts} +3 -1
- package/dist/guest/{audit.js → audit/process-audit.js} +33 -8
- package/dist/guest/boot/boot-env.d.ts +4 -0
- package/dist/guest/{boot-env.js → boot/boot-env.js} +7 -5
- package/dist/guest/boot/boot.d.ts +1 -0
- package/dist/guest/{main.js → boot/boot.js} +100 -50
- package/dist/guest/{guide.js → boot/guide.js} +32 -7
- package/dist/guest/{project-env.d.ts → boot/project-env.d.ts} +3 -3
- package/dist/guest/{project-env.js → boot/project-env.js} +12 -4
- package/dist/guest/boot/project-status.d.ts +5 -0
- package/dist/guest/boot/project-status.js +28 -0
- package/dist/guest/daemon/daemon.d.ts +1 -0
- package/dist/guest/daemon/daemon.js +51 -0
- package/dist/guest/daemon/exec.js +18 -6
- package/dist/guest/daemon/{shutdown.js → idle-shutdown.js} +5 -4
- package/dist/guest/daemon/{project.d.ts → project-provisioner.d.ts} +3 -3
- package/dist/guest/daemon/{project.js → project-provisioner.js} +60 -22
- package/dist/guest/daemon/relays.js +5 -3
- package/dist/guest/daemon/{session.js → sessions.js} +84 -24
- package/dist/guest/daemon/state.d.ts +4 -1
- package/dist/guest/daemon/state.js +34 -20
- package/dist/guest/databases/database-server.d.ts +13 -0
- package/dist/guest/databases/database-server.js +35 -0
- package/dist/guest/databases/dynamodb.d.ts +12 -0
- package/dist/guest/databases/dynamodb.js +81 -0
- package/dist/guest/databases/index.d.ts +2 -0
- package/dist/guest/databases/index.js +2 -0
- package/dist/guest/databases/mongodb.d.ts +7 -0
- package/dist/guest/databases/mongodb.js +46 -0
- package/dist/guest/databases/mysql.d.ts +7 -0
- package/dist/guest/databases/mysql.js +59 -0
- package/dist/guest/databases/names.d.ts +5 -0
- package/dist/guest/databases/names.js +8 -0
- package/dist/guest/databases/postgres.d.ts +9 -0
- package/dist/guest/databases/postgres.js +85 -0
- package/dist/guest/databases/redis.d.ts +7 -0
- package/dist/guest/databases/redis.js +25 -0
- package/dist/guest/databases/registry.d.ts +5 -0
- package/dist/guest/databases/registry.js +51 -0
- package/dist/guest/databases/sbx-db.d.ts +1 -0
- package/dist/guest/{db.js → databases/sbx-db.js} +13 -13
- package/dist/guest/{toolchains/databases → databases}/server.d.ts +5 -5
- package/dist/guest/{toolchains/databases → databases}/server.js +18 -13
- package/dist/guest/entries/daemon.js +16 -0
- package/dist/guest/entries/db.js +10 -0
- package/dist/guest/entries/gitguard.js +20 -0
- package/dist/guest/entries/main.d.ts +1 -0
- package/dist/guest/entries/main.js +24 -0
- package/dist/guest/entries/netproxy.d.ts +1 -0
- package/dist/guest/entries/netproxy.js +7 -0
- package/dist/guest/entries/view.d.ts +1 -0
- package/dist/guest/entries/view.js +11 -0
- package/dist/guest/{gitguard.js → git/decision.js} +49 -26
- package/dist/guest/network/addresses.d.ts +2 -0
- package/dist/guest/network/addresses.js +6 -0
- package/dist/guest/{setup/network.d.ts → network/allow-only.d.ts} +0 -10
- package/dist/guest/network/allow-only.js +84 -0
- package/dist/guest/network/firewall.d.ts +9 -0
- package/dist/guest/{setup/network.js → network/firewall.js} +58 -63
- package/dist/guest/network/proxy-server.d.ts +2 -0
- package/dist/guest/{netproxy.js → network/proxy-server.js} +37 -18
- package/dist/guest/{helpers.d.ts → runtime/csc.d.ts} +1 -1
- package/dist/guest/{helpers.js → runtime/csc.js} +7 -2
- package/dist/guest/runtime/fs.d.ts +2 -0
- package/dist/guest/runtime/fs.js +6 -0
- package/dist/guest/runtime/log.d.ts +3 -0
- package/dist/guest/runtime/log.js +22 -0
- package/dist/guest/runtime/paths.d.ts +13 -0
- package/dist/guest/runtime/paths.js +14 -0
- package/dist/guest/{ports.js → runtime/ports.js} +8 -2
- package/dist/guest/runtime/process.d.ts +15 -0
- package/dist/guest/runtime/process.js +59 -0
- package/dist/guest/{project-context.js → runtime/project-context.js} +1 -1
- package/dist/guest/runtime/session.d.ts +5 -0
- package/dist/guest/runtime/session.js +10 -0
- package/dist/guest/runtime/status.d.ts +7 -0
- package/dist/guest/runtime/status.js +57 -0
- package/dist/guest/{cmdline.js → sessions/cmdline.js} +10 -4
- package/dist/guest/{ptyhost.js → sessions/pty-host.js} +12 -5
- package/dist/guest/{view.js → sessions/viewer.js} +8 -11
- package/dist/guest/setup/claude-mem.d.ts +10 -0
- package/dist/guest/setup/{claude.js → claude-mem.js} +18 -78
- package/dist/guest/setup/{claude.d.ts → claude-profile.d.ts} +0 -10
- package/dist/guest/setup/claude-profile.js +89 -0
- package/dist/guest/setup/desktop.d.ts +2 -0
- package/dist/guest/setup/desktop.js +32 -0
- package/dist/guest/setup/environment.js +28 -5
- package/dist/guest/setup/{user.d.ts → git-identity.d.ts} +0 -2
- package/dist/guest/setup/git-identity.js +34 -0
- package/dist/guest/{gitrules.d.ts → setup/git-rules.d.ts} +1 -1
- package/dist/guest/setup/git-rules.js +50 -0
- package/dist/guest/setup/hooks.js +22 -5
- package/dist/guest/setup/{policy.js → managed-policy.js} +2 -2
- package/dist/guest/toolchains/catalogue.d.ts +4 -4
- package/dist/guest/toolchains/catalogue.js +30 -7
- package/dist/guest/toolchains/detect.d.ts +12 -0
- package/dist/guest/toolchains/detect.js +54 -0
- package/dist/guest/toolchains/index.d.ts +3 -17
- package/dist/guest/toolchains/index.js +1 -80
- package/dist/guest/toolchains/install.d.ts +20 -0
- package/dist/guest/toolchains/install.js +29 -0
- package/dist/guest/toolchains/languages/go.d.ts +3 -0
- package/dist/guest/toolchains/{go.js → languages/go.js} +27 -9
- package/dist/guest/toolchains/languages/java.d.ts +8 -0
- package/dist/guest/toolchains/{java.js → languages/java.js} +57 -18
- package/dist/guest/toolchains/languages/node.d.ts +3 -0
- package/dist/guest/toolchains/{node.js → languages/node.js} +51 -18
- package/dist/guest/toolchains/languages/php.d.ts +3 -0
- package/dist/guest/toolchains/{scripting → languages}/php.js +36 -11
- package/dist/guest/toolchains/languages/python-tools.d.ts +3 -0
- package/dist/guest/toolchains/languages/python-tools.js +12 -0
- package/dist/guest/toolchains/languages/python.d.ts +3 -0
- package/dist/guest/toolchains/{python.js → languages/python.js} +29 -16
- package/dist/guest/toolchains/languages/ruby.d.ts +3 -0
- package/dist/guest/toolchains/{scripting → languages}/ruby.js +28 -10
- package/dist/guest/toolchains/leftovers.d.ts +1 -1
- package/dist/guest/toolchains/leftovers.js +13 -11
- package/dist/guest/toolchains/managers.d.ts +6 -6
- package/dist/guest/toolchains/managers.js +38 -17
- package/dist/guest/toolchains/native/binstall.d.ts +3 -2
- package/dist/guest/toolchains/native/binstall.js +20 -8
- package/dist/guest/toolchains/native/cpp.d.ts +2 -2
- package/dist/guest/toolchains/native/cpp.js +23 -8
- package/dist/guest/toolchains/native/dotnet.d.ts +5 -3
- package/dist/guest/toolchains/native/dotnet.js +72 -24
- package/dist/guest/toolchains/native/mesa.d.ts +2 -2
- package/dist/guest/toolchains/native/mesa.js +27 -10
- package/dist/guest/toolchains/native/msvc/environment.d.ts +4 -4
- package/dist/guest/toolchains/native/msvc/environment.js +30 -16
- package/dist/guest/toolchains/native/msvc/index.d.ts +3 -3
- package/dist/guest/toolchains/native/msvc/index.js +10 -8
- package/dist/guest/toolchains/native/msvc/packages.d.ts +1 -1
- package/dist/guest/toolchains/native/msvc/packages.js +69 -23
- package/dist/guest/toolchains/native/msvc/tree.d.ts +6 -6
- package/dist/guest/toolchains/native/msvc/tree.js +15 -9
- package/dist/guest/toolchains/native/rust-extras.d.ts +23 -0
- package/dist/guest/toolchains/native/rust-extras.js +100 -0
- package/dist/guest/toolchains/native/rust.d.ts +2 -2
- package/dist/guest/toolchains/native/rust.js +41 -10
- package/dist/guest/toolchains/{scripting → native}/vcruntime.d.ts +2 -2
- package/dist/guest/toolchains/{scripting → native}/vcruntime.js +17 -7
- package/dist/guest/toolchains/package-ledger.d.ts +17 -0
- package/dist/guest/toolchains/package-ledger.js +54 -0
- package/dist/guest/toolchains/plan.d.ts +3 -24
- package/dist/guest/toolchains/plan.js +99 -111
- package/dist/guest/toolchains/runtimes.d.ts +6 -6
- package/dist/guest/toolchains/runtimes.js +31 -13
- package/dist/guest/toolchains/scheduler.d.ts +22 -0
- package/dist/guest/toolchains/scheduler.js +123 -0
- package/dist/guest/toolchains/setup.d.ts +10 -0
- package/dist/guest/toolchains/setup.js +22 -0
- package/dist/guest/toolchains/state-file.d.ts +3 -0
- package/dist/guest/toolchains/state-file.js +10 -0
- package/dist/guest/toolchains/step.d.ts +24 -0
- package/dist/guest/toolchains/step.js +1 -0
- package/dist/guest/toolchains/tool-env.d.ts +12 -0
- package/dist/guest/toolchains/tool-env.js +16 -0
- package/dist/guest/toolchains/tools/cli.d.ts +10 -0
- package/dist/guest/toolchains/{cli.js → tools/cli.js} +35 -15
- package/dist/guest/toolchains/tools/git.d.ts +3 -0
- package/dist/guest/toolchains/{git.js → tools/git.js} +38 -15
- package/dist/guest/toolchains/tools/pwsh.d.ts +4 -0
- package/dist/guest/toolchains/{pwsh.js → tools/pwsh.js} +14 -7
- package/dist/guest/toolchains/{vscode-profile.d.ts → tools/vscode-profile.d.ts} +6 -6
- package/dist/guest/toolchains/{vscode-profile.js → tools/vscode-profile.js} +28 -12
- package/dist/guest/toolchains/{vscode.d.ts → tools/vscode.d.ts} +6 -6
- package/dist/guest/toolchains/{vscode.js → tools/vscode.js} +67 -21
- package/dist/guest/toolchains/version-cache.d.ts +16 -0
- package/dist/guest/toolchains/version-cache.js +67 -0
- package/dist/host/agent-commands/commands.d.ts +13 -0
- package/dist/host/agent-commands/commands.js +33 -0
- package/dist/host/agent-commands/forwarders.d.ts +7 -0
- package/dist/host/agent-commands/forwarders.js +31 -0
- package/dist/host/agent-commands/index.d.ts +4 -0
- package/dist/host/agent-commands/index.js +4 -0
- package/dist/host/agent-commands/reconcile.d.ts +12 -0
- package/dist/host/agent-commands/reconcile.js +69 -0
- package/dist/host/agent-commands/user-path.d.ts +2 -0
- package/dist/host/agent-commands/user-path.js +33 -0
- package/dist/host/audit/collect.d.ts +2 -2
- package/dist/host/audit/collect.js +59 -22
- package/dist/host/audit/log.d.ts +2 -2
- package/dist/host/audit/log.js +24 -8
- package/dist/host/{attach.d.ts → channel/attach.d.ts} +2 -2
- package/dist/host/{attach.js → channel/attach.js} +33 -15
- package/dist/host/channel/channel.d.ts +51 -0
- package/dist/host/channel/channel.js +196 -0
- package/dist/host/channel/index.d.ts +2 -0
- package/dist/host/channel/index.js +2 -0
- package/dist/host/guard/agent-files.d.ts +7 -0
- package/dist/host/guard/agent-files.js +103 -0
- package/dist/host/guard/commands.d.ts +10 -0
- package/dist/host/guard/commands.js +123 -0
- package/dist/host/guard/file-hash.d.ts +4 -0
- package/dist/host/guard/file-hash.js +37 -0
- package/dist/host/guard/git-config.d.ts +5 -0
- package/dist/host/guard/git-config.js +62 -0
- package/dist/host/guard/git-dirs.d.ts +12 -0
- package/dist/host/guard/git-dirs.js +53 -0
- package/dist/host/guard/index.d.ts +5 -0
- package/dist/host/guard/index.js +4 -0
- package/dist/host/guard/mark-of-the-web.d.ts +8 -0
- package/dist/host/guard/mark-of-the-web.js +74 -0
- package/dist/host/guard/nested-repos.d.ts +14 -0
- package/dist/host/guard/nested-repos.js +88 -0
- package/dist/host/guard/quarantine.d.ts +3 -0
- package/dist/host/guard/quarantine.js +24 -0
- package/dist/host/guard/repo-guard.d.ts +10 -0
- package/dist/host/guard/repo-guard.js +36 -0
- package/dist/host/guard/store.d.ts +40 -0
- package/dist/host/guard/store.js +145 -0
- package/dist/host/guard/types.d.ts +27 -0
- package/dist/host/guard/types.js +3 -0
- package/dist/host/guard/watch-state.d.ts +9 -0
- package/dist/host/guard/watch-state.js +26 -0
- package/dist/host/launch/boot-projects.d.ts +17 -0
- package/dist/host/launch/{projects.js → boot-projects.js} +27 -12
- package/dist/host/{database-plan.d.ts → launch/database-plan.d.ts} +5 -5
- package/dist/host/{database-plan.js → launch/database-plan.js} +24 -13
- package/dist/host/launch/generate.d.ts +4 -0
- package/dist/host/launch/generate.js +77 -0
- package/dist/host/launch/index.d.ts +10 -0
- package/dist/host/launch/index.js +10 -0
- package/dist/host/launch/mappings.d.ts +7 -2
- package/dist/host/launch/mappings.js +83 -24
- package/dist/host/launch/pc-scan.d.ts +5 -0
- package/dist/host/{pc-scan.js → launch/pc-scan.js} +20 -13
- package/dist/host/launch/project-scan.d.ts +7 -0
- package/dist/host/{project-scan.js → launch/project-scan.js} +29 -21
- package/dist/host/launch/session-file.d.ts +23 -0
- package/dist/host/launch/session-file.js +73 -0
- package/dist/host/launch/stage.d.ts +5 -5
- package/dist/host/launch/stage.js +14 -13
- package/dist/host/launch/toolchains.d.ts +4 -0
- package/dist/host/launch/toolchains.js +11 -0
- package/dist/host/launch/{wsb.d.ts → wsb-file.d.ts} +4 -2
- package/dist/host/launch/wsb-file.js +56 -0
- package/dist/host/life/crash-report.d.ts +8 -0
- package/dist/host/life/crash-report.js +87 -0
- package/dist/host/life/index.d.ts +6 -0
- package/dist/host/life/index.js +6 -0
- package/dist/host/life/keep-awake.d.ts +10 -0
- package/dist/host/life/keep-awake.js +29 -0
- package/dist/host/life/life-record.d.ts +48 -0
- package/dist/host/life/life-record.js +76 -0
- package/dist/host/life/stop-events.d.ts +27 -0
- package/dist/host/life/stop-events.js +96 -0
- package/dist/host/life/stop-warning.d.ts +4 -0
- package/dist/host/life/stop-warning.js +25 -0
- package/dist/host/life/windows-update.d.ts +3 -0
- package/dist/host/life/windows-update.js +11 -0
- package/dist/host/native.d.ts +4 -0
- package/dist/host/native.js +11 -0
- package/dist/host/network/index.d.ts +1 -0
- package/dist/host/network/index.js +1 -0
- package/dist/host/{port-forward.d.ts → network/port-forward.d.ts} +1 -1
- package/dist/host/{port-forward.js → network/port-forward.js} +16 -10
- package/dist/host/profile/accounts.d.ts +37 -0
- package/dist/host/profile/accounts.js +146 -0
- package/dist/host/profile/claude-login.d.ts +22 -0
- package/dist/host/profile/claude-login.js +57 -0
- package/dist/host/{claude-profile.d.ts → profile/claude-profile.d.ts} +9 -9
- package/dist/host/{claude-profile.js → profile/claude-profile.js} +32 -22
- package/dist/host/profile/index.d.ts +7 -0
- package/dist/host/profile/index.js +7 -0
- package/dist/host/profile/personalize.d.ts +2 -0
- package/dist/host/profile/personalize.js +127 -0
- package/dist/host/profile/reg-file.d.ts +8 -0
- package/dist/host/profile/reg-file.js +45 -0
- package/dist/host/profile/secret-files.d.ts +2 -0
- package/dist/host/profile/secret-files.js +25 -0
- package/dist/host/profile/secret-patterns.d.ts +6 -0
- package/dist/host/profile/secret-patterns.js +128 -0
- package/dist/host/profile/secrets.d.ts +12 -0
- package/dist/host/profile/secrets.js +100 -0
- package/dist/host/projects/index.d.ts +4 -0
- package/dist/host/projects/index.js +4 -0
- package/dist/host/projects/join.d.ts +38 -0
- package/dist/host/projects/join.js +119 -0
- package/dist/host/projects/known.d.ts +28 -0
- package/dist/host/projects/known.js +55 -0
- package/dist/host/projects/mapper.d.ts +29 -0
- package/dist/host/projects/mapper.js +88 -0
- package/dist/host/projects/registry.d.ts +83 -0
- package/dist/host/projects/registry.js +136 -0
- package/dist/host/sandbox/doctor.d.ts +2 -0
- package/dist/host/sandbox/doctor.js +42 -0
- package/dist/host/sandbox/host-claude.d.ts +1 -0
- package/dist/host/sandbox/host-claude.js +26 -0
- package/dist/host/sandbox/index.d.ts +6 -0
- package/dist/host/sandbox/index.js +6 -0
- package/dist/host/{platform.d.ts → sandbox/platform.d.ts} +0 -5
- package/dist/host/sandbox/platform.js +60 -0
- package/dist/host/sandbox/probe.d.ts +3 -0
- package/dist/host/sandbox/probe.js +47 -0
- package/dist/host/{window.js → sandbox/window.js} +7 -5
- package/dist/host/{wsb.js → sandbox/wsb-cli.js} +31 -8
- package/dist/host/{cleanup.js → storage/cleanup.js} +27 -12
- package/dist/host/storage/index.d.ts +2 -0
- package/dist/host/storage/index.js +2 -0
- package/dist/host/storage/state-files.d.ts +4 -0
- package/dist/host/storage/state-files.js +10 -0
- package/dist/host/test-guard.js +1 -1
- package/dist/host/tools/conpty.d.ts +8 -0
- package/dist/host/tools/conpty.js +58 -0
- package/dist/host/tools/index.d.ts +2 -0
- package/dist/host/tools/index.js +2 -0
- package/dist/host/{terminal.d.ts → tools/windows-terminal.d.ts} +2 -10
- package/dist/host/{terminal.js → tools/windows-terminal.js} +33 -57
- package/dist/host/workspace-view/active-views.d.ts +3 -0
- package/dist/host/workspace-view/active-views.js +22 -0
- package/dist/host/workspace-view/index.d.ts +2 -18
- package/dist/host/workspace-view/index.js +2 -49
- package/dist/host/workspace-view/plan.d.ts +16 -0
- package/dist/host/workspace-view/plan.js +50 -0
- package/dist/host/workspace-view/rules.js +10 -3
- package/dist/host/workspace-view/view-state.d.ts +10 -0
- package/dist/host/workspace-view/view-state.js +31 -0
- package/dist/host/workspace-view/view.d.ts +1 -0
- package/dist/host/workspace-view/view.js +51 -55
- package/dist/runtime/daemon.js +4232 -1918
- package/dist/runtime/db.js +2145 -830
- package/dist/runtime/gitguard.js +29 -11
- package/dist/runtime/main.js +4760 -2155
- package/dist/runtime/netproxy.js +1654 -418
- package/dist/runtime/view.js +1515 -453
- package/dist/selftest/accounts.test.d.ts +1 -1
- package/dist/selftest/accounts.test.js +20 -17
- package/dist/selftest/agent-commands.test.d.ts +1 -1
- package/dist/selftest/agent-commands.test.js +9 -5
- package/dist/selftest/audit.test.d.ts +1 -1
- package/dist/selftest/audit.test.js +46 -13
- package/dist/selftest/channel.test.d.ts +1 -1
- package/dist/selftest/channel.test.js +91 -8
- package/dist/selftest/cli.test.d.ts +1 -1
- package/dist/selftest/cli.test.js +68 -16
- package/dist/selftest/cmdline.test.d.ts +1 -1
- package/dist/selftest/cmdline.test.js +36 -7
- package/dist/selftest/config.test.d.ts +1 -1
- package/dist/selftest/config.test.js +12 -5
- package/dist/selftest/data.test.d.ts +1 -1
- package/dist/selftest/data.test.js +35 -6
- package/dist/selftest/detect.test.d.ts +1 -1
- package/dist/selftest/detect.test.js +22 -9
- package/dist/selftest/generate.test.d.ts +1 -1
- package/dist/selftest/generate.test.js +33 -9
- package/dist/selftest/git-access.test.d.ts +1 -1
- package/dist/selftest/git-access.test.js +42 -4
- package/dist/selftest/guest-boot.test.d.ts +1 -1
- package/dist/selftest/guest-boot.test.js +25 -7
- package/dist/selftest/host-sim.test.d.ts +1 -1
- package/dist/selftest/host-sim.test.js +27 -3
- package/dist/selftest/hostile-input.test.d.ts +1 -1
- package/dist/selftest/hostile-input.test.js +5 -5
- package/dist/selftest/index.d.ts +1 -1
- package/dist/selftest/index.js +73 -16
- package/dist/selftest/layout.test.d.ts +2 -0
- package/dist/selftest/layout.test.js +131 -0
- package/dist/selftest/links.test.d.ts +1 -1
- package/dist/selftest/links.test.js +16 -11
- package/dist/selftest/live-daemon.test.d.ts +1 -1
- package/dist/selftest/live-daemon.test.js +20 -8
- package/dist/selftest/live-git.test.d.ts +1 -1
- package/dist/selftest/live-git.test.js +13 -4
- package/dist/selftest/live-network.test.d.ts +1 -1
- package/dist/selftest/live-network.test.js +24 -9
- package/dist/selftest/live-projects.test.d.ts +1 -1
- package/dist/selftest/live-projects.test.js +47 -20
- package/dist/selftest/live-terminal.test.d.ts +2 -0
- package/dist/selftest/live-terminal.test.js +195 -0
- package/dist/selftest/local-config.test.d.ts +1 -1
- package/dist/selftest/local-config.test.js +88 -15
- package/dist/selftest/mirror.test.d.ts +1 -1
- package/dist/selftest/mirror.test.js +118 -19
- package/dist/selftest/network.test.d.ts +1 -1
- package/dist/selftest/network.test.js +17 -8
- package/dist/selftest/personalization.test.d.ts +1 -1
- package/dist/selftest/personalization.test.js +12 -5
- package/dist/selftest/projects.test.d.ts +1 -1
- package/dist/selftest/projects.test.js +336 -72
- package/dist/selftest/repair.test.d.ts +1 -1
- package/dist/selftest/repair.test.js +17 -5
- package/dist/selftest/repo-guard.test.d.ts +1 -1
- package/dist/selftest/repo-guard.test.js +21 -20
- package/dist/selftest/secrets.test.d.ts +1 -1
- package/dist/selftest/secrets.test.js +57 -13
- package/dist/selftest/setup.test.d.ts +1 -1
- package/dist/selftest/setup.test.js +25 -5
- package/dist/selftest/{fixtures.d.ts → support/fixtures.d.ts} +7 -4
- package/dist/selftest/{fixtures.js → support/fixtures.js} +95 -17
- package/dist/selftest/{harness.js → support/harness.js} +24 -7
- package/dist/selftest/{live.d.ts → support/live.d.ts} +2 -2
- package/dist/selftest/{live.js → support/live.js} +34 -10
- package/dist/selftest/support/suite.js +1 -0
- package/dist/selftest/sync.test.d.ts +1 -1
- package/dist/selftest/sync.test.js +64 -26
- package/dist/selftest/test-guard.test.d.ts +1 -1
- package/dist/selftest/test-guard.test.js +43 -15
- package/dist/selftest/toolchains.test.d.ts +1 -1
- package/dist/selftest/toolchains.test.js +135 -36
- package/dist/selftest/workspace-view.test.d.ts +1 -1
- package/dist/selftest/workspace-view.test.js +48 -11
- package/dist/selftest/workspace.test.d.ts +1 -1
- package/dist/selftest/workspace.test.js +13 -4
- package/dist/shared/{apps.d.ts → apps/catalogue.d.ts} +1 -11
- package/dist/shared/apps/catalogue.js +768 -0
- package/dist/shared/apps/index.d.ts +2 -0
- package/dist/shared/apps/index.js +2 -0
- package/dist/shared/apps/selection.d.ts +11 -0
- package/dist/shared/apps/selection.js +40 -0
- package/dist/shared/channel/index.d.ts +2 -0
- package/dist/shared/channel/index.js +2 -0
- package/dist/shared/channel/run-dir.d.ts +30 -0
- package/dist/shared/channel/run-dir.js +84 -0
- package/dist/shared/{schema.d.ts → channel/schema.d.ts} +60 -19
- package/dist/shared/channel/schema.js +131 -0
- package/dist/shared/download/archive.d.ts +13 -0
- package/dist/shared/download/archive.js +57 -0
- package/dist/shared/download/downloader.d.ts +35 -0
- package/dist/shared/download/downloader.js +110 -0
- package/dist/shared/download/github.d.ts +16 -0
- package/dist/shared/download/github.js +74 -0
- package/dist/shared/download/http.d.ts +5 -0
- package/dist/shared/download/http.js +30 -0
- package/dist/shared/download/index.d.ts +5 -0
- package/dist/shared/download/index.js +5 -0
- package/dist/shared/download/spawn.d.ts +2 -0
- package/dist/shared/download/spawn.js +7 -0
- package/dist/shared/io/index.d.ts +3 -0
- package/dist/shared/io/index.js +3 -0
- package/dist/shared/io/json-file.d.ts +10 -0
- package/dist/shared/io/json-file.js +21 -0
- package/dist/shared/io/json.d.ts +13 -0
- package/dist/shared/io/json.js +49 -0
- package/dist/shared/{safe-remove.js → io/safe-remove.js} +32 -7
- package/dist/shared/{netrules.js → network/firewall-rules.js} +36 -5
- package/dist/shared/network/index.d.ts +2 -0
- package/dist/shared/network/index.js +2 -0
- package/dist/shared/{netpolicy.js → network/policy.js} +66 -11
- package/dist/shared/{paths.js → paths/claude-paths.js} +12 -2
- package/dist/shared/{guest-paths.d.ts → paths/guest-paths.d.ts} +21 -0
- package/dist/shared/paths/guest-paths.js +146 -0
- package/dist/shared/paths/index.d.ts +3 -0
- package/dist/shared/paths/index.js +3 -0
- package/dist/shared/{projects.d.ts → paths/projects.d.ts} +27 -4
- package/dist/shared/paths/projects.js +136 -0
- package/dist/shared/pty/client.d.ts +21 -0
- package/dist/shared/pty/client.js +79 -0
- package/dist/shared/pty/console-input.d.ts +11 -0
- package/dist/shared/pty/console-input.js +81 -0
- package/dist/shared/pty/index.d.ts +6 -0
- package/dist/shared/pty/index.js +6 -0
- package/dist/shared/pty/input-joiner.d.ts +15 -0
- package/dist/shared/pty/input-joiner.js +44 -0
- package/dist/shared/pty/output-filter.d.ts +13 -0
- package/dist/shared/pty/output-filter.js +140 -0
- package/dist/shared/pty/protocol.d.ts +36 -0
- package/dist/shared/pty/protocol.js +60 -0
- package/dist/shared/pty/terminal.d.ts +24 -0
- package/dist/shared/pty/terminal.js +147 -0
- package/dist/shared/test-guard.js +3 -1
- package/dist/sync/claude-mem.d.ts +1 -1
- package/dist/sync/claude-mem.js +9 -4
- package/dist/sync/history.d.ts +1 -29
- package/dist/sync/history.js +57 -45
- package/dist/sync/index.d.ts +5 -0
- package/dist/sync/index.js +5 -0
- package/dist/sync/sync-cycle.d.ts +18 -0
- package/dist/sync/sync-cycle.js +85 -0
- package/dist/sync/sync-state.d.ts +32 -0
- package/dist/sync/sync-state.js +37 -0
- package/dist/sync/watcher.d.ts +0 -18
- package/dist/sync/watcher.js +66 -100
- package/native/keep-awake.ps1 +8 -0
- package/native/power.cs +23 -0
- package/native/stop-events.ps1 +38 -0
- package/package.json +11 -3
- package/sandbox/linkgate.cs +98 -0
- package/sandbox/memlog.ps1 +15 -6
- package/sandbox/ptyhost.cs +60 -3
- package/schemas/config.schema.json +48 -1
- package/schemas/sandbox-config.schema.json +37 -3
- package/dist/cli/commands/launch.d.ts +0 -29
- package/dist/cli/commands/launch.js +0 -366
- package/dist/cli/commands/maintenance.d.ts +0 -10
- package/dist/cli/commands/maintenance.js +0 -187
- package/dist/cli/commands/project.d.ts +0 -29
- package/dist/cli/commands/project.js +0 -63
- package/dist/cli/commands/projects.d.ts +0 -14
- package/dist/cli/commands/projects.js +0 -146
- package/dist/cli/commands/restart.d.ts +0 -6
- package/dist/cli/commands/restart.js +0 -85
- package/dist/cli/commands/sessions.d.ts +0 -12
- package/dist/cli/commands/sessions.js +0 -257
- package/dist/cli/menu/settings/editors.js +0 -305
- package/dist/cli/progress.d.ts +0 -9
- package/dist/cli/progress.js +0 -49
- package/dist/cli/tui/dialogs.d.ts +0 -57
- package/dist/cli/tui/dialogs.js +0 -162
- package/dist/core/config.js +0 -109
- package/dist/core/schema.d.ts +0 -6
- package/dist/core/schema.js +0 -8
- package/dist/core/util.d.ts +0 -62
- package/dist/core/util.js +0 -156
- package/dist/core/workspace.d.ts +0 -18
- package/dist/core/workspace.js +0 -145
- package/dist/guest/boot-env.d.ts +0 -4
- package/dist/guest/daemon.js +0 -57
- package/dist/guest/env.d.ts +0 -52
- package/dist/guest/env.js +0 -103
- package/dist/guest/gitrules.js +0 -11
- package/dist/guest/project-status.d.ts +0 -5
- package/dist/guest/project-status.js +0 -17
- package/dist/guest/setup/user.js +0 -51
- package/dist/guest/toolchains/cli.d.ts +0 -10
- package/dist/guest/toolchains/common.d.ts +0 -54
- package/dist/guest/toolchains/common.js +0 -147
- package/dist/guest/toolchains/databases/dynamodb.d.ts +0 -8
- package/dist/guest/toolchains/databases/dynamodb.js +0 -52
- package/dist/guest/toolchains/databases/index.d.ts +0 -6
- package/dist/guest/toolchains/databases/index.js +0 -62
- package/dist/guest/toolchains/databases/mongodb.d.ts +0 -3
- package/dist/guest/toolchains/databases/mongodb.js +0 -31
- package/dist/guest/toolchains/databases/mysql.d.ts +0 -3
- package/dist/guest/toolchains/databases/mysql.js +0 -38
- package/dist/guest/toolchains/databases/postgres.d.ts +0 -5
- package/dist/guest/toolchains/databases/postgres.js +0 -38
- package/dist/guest/toolchains/databases/redis.d.ts +0 -3
- package/dist/guest/toolchains/databases/redis.js +0 -16
- package/dist/guest/toolchains/git.d.ts +0 -3
- package/dist/guest/toolchains/go.d.ts +0 -3
- package/dist/guest/toolchains/java.d.ts +0 -8
- package/dist/guest/toolchains/node.d.ts +0 -3
- package/dist/guest/toolchains/pwsh.d.ts +0 -4
- package/dist/guest/toolchains/python.d.ts +0 -3
- package/dist/guest/toolchains/scripting/php.d.ts +0 -3
- package/dist/guest/toolchains/scripting/ruby.d.ts +0 -3
- package/dist/host/accounts.d.ts +0 -32
- package/dist/host/accounts.js +0 -128
- package/dist/host/agent-commands.d.ts +0 -25
- package/dist/host/agent-commands.js +0 -145
- package/dist/host/channel.d.ts +0 -38
- package/dist/host/channel.js +0 -162
- package/dist/host/generate.d.ts +0 -13
- package/dist/host/generate.js +0 -108
- package/dist/host/join.d.ts +0 -28
- package/dist/host/join.js +0 -76
- package/dist/host/launch/projects.d.ts +0 -15
- package/dist/host/launch/wsb.js +0 -34
- package/dist/host/motw.d.ts +0 -17
- package/dist/host/motw.js +0 -74
- package/dist/host/pc-scan.d.ts +0 -6
- package/dist/host/personalize.d.ts +0 -10
- package/dist/host/personalize.js +0 -97
- package/dist/host/platform.js +0 -129
- package/dist/host/project-scan.d.ts +0 -7
- package/dist/host/projects.d.ts +0 -100
- package/dist/host/projects.js +0 -147
- package/dist/host/repo-guard.d.ts +0 -43
- package/dist/host/repo-guard.js +0 -347
- package/dist/host/secrets.d.ts +0 -14
- package/dist/host/secrets.js +0 -133
- package/dist/host/stops.d.ts +0 -67
- package/dist/host/stops.js +0 -126
- package/dist/shared/apps.js +0 -114
- package/dist/shared/download.d.ts +0 -60
- package/dist/shared/download.js +0 -215
- package/dist/shared/guest-paths.js +0 -61
- package/dist/shared/projects.js +0 -67
- package/dist/shared/pty-client.d.ts +0 -91
- package/dist/shared/pty-client.js +0 -349
- package/dist/shared/rundir.d.ts +0 -41
- package/dist/shared/rundir.js +0 -96
- package/dist/shared/schema.js +0 -92
- /package/dist/{guest/daemon.d.ts → cli/tui/list/list-types.js} +0 -0
- /package/dist/{guest/db.d.ts → cli/tui/screen.js} +0 -0
- /package/dist/core/{detect-databases.d.ts → detect/databases.d.ts} +0 -0
- /package/dist/{guest/toolchains → core/detect}/versions.d.ts +0 -0
- /package/dist/guest/{setup/agents.d.ts → agents/agent-installer.d.ts} +0 -0
- /package/dist/guest/{audit-parse.d.ts → audit/parse.d.ts} +0 -0
- /package/dist/guest/{guide.d.ts → boot/guide.d.ts} +0 -0
- /package/dist/guest/daemon/{shutdown.d.ts → idle-shutdown.d.ts} +0 -0
- /package/dist/guest/daemon/{session.d.ts → sessions.d.ts} +0 -0
- /package/dist/guest/{main.d.ts → entries/daemon.d.ts} +0 -0
- /package/dist/guest/{netproxy.d.ts → entries/db.d.ts} +0 -0
- /package/dist/{selftest/suite.js → guest/entries/gitguard.d.ts} +0 -0
- /package/dist/guest/{gitguard.d.ts → git/decision.d.ts} +0 -0
- /package/dist/guest/{ports.d.ts → runtime/ports.d.ts} +0 -0
- /package/dist/guest/{project-context.d.ts → runtime/project-context.d.ts} +0 -0
- /package/dist/guest/{cmdline.d.ts → sessions/cmdline.d.ts} +0 -0
- /package/dist/guest/{ptyhost.d.ts → sessions/pty-host.d.ts} +0 -0
- /package/dist/guest/{view.d.ts → sessions/viewer.d.ts} +0 -0
- /package/dist/guest/setup/{policy.d.ts → managed-policy.d.ts} +0 -0
- /package/dist/host/{window.d.ts → sandbox/window.d.ts} +0 -0
- /package/dist/host/{wsb.d.ts → sandbox/wsb-cli.d.ts} +0 -0
- /package/dist/host/{cleanup.d.ts → storage/cleanup.d.ts} +0 -0
- /package/dist/selftest/{harness.d.ts → support/harness.d.ts} +0 -0
- /package/dist/selftest/{suite.d.ts → support/suite.d.ts} +0 -0
- /package/dist/shared/{safe-remove.d.ts → io/safe-remove.d.ts} +0 -0
- /package/dist/shared/{netrules.d.ts → network/firewall-rules.d.ts} +0 -0
- /package/dist/shared/{netpolicy.d.ts → network/policy.d.ts} +0 -0
- /package/dist/shared/{paths.d.ts → paths/claude-paths.d.ts} +0 -0
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
// PowerShell 7 profile. The Windows Terminal part is only tried on temp copies.
|
|
3
3
|
import fs from 'node:fs';
|
|
4
4
|
import path from 'node:path';
|
|
5
|
-
import { toRegFile } from '../host/
|
|
6
|
-
import { PWSH_PROFILE_GUID, syncPwshProfile, withPwshProfile } from '../host/
|
|
5
|
+
import { toRegFile } from '../host/profile/index.js';
|
|
6
|
+
import { PWSH_PROFILE_GUID, syncPwshProfile, withPwshProfile } from '../host/tools/index.js';
|
|
7
7
|
export const personalizationSuite = {
|
|
8
8
|
name: 'personalization',
|
|
9
9
|
title: 'registry personalisation (.reg) and the Windows Terminal PowerShell 7 profile',
|
|
@@ -27,9 +27,16 @@ export const personalizationSuite = {
|
|
|
27
27
|
t.check(Boolean(shownProfiles?.defaults) && shown?.theme === 'dark', 'the rest of the settings are kept');
|
|
28
28
|
t.equal(withPwshProfile(shown, true), null, 'nothing is rewritten when the profile is already there');
|
|
29
29
|
t.equal(withPwshProfile({ profiles: { defaults: {} } }, false), null, 'nothing is rewritten when pwsh was never wanted');
|
|
30
|
-
const edited = {
|
|
30
|
+
const edited = {
|
|
31
|
+
profiles: { list: [{ guid: 'other' }, { guid: PWSH_PROFILE_GUID.toUpperCase(), name: 'My pwsh', fontSize: 14 }] },
|
|
32
|
+
};
|
|
31
33
|
const hidden = withPwshProfile(edited, false)?.profiles;
|
|
32
|
-
t.equal({
|
|
34
|
+
t.equal({
|
|
35
|
+
hidden: hidden?.list[1].hidden,
|
|
36
|
+
name: hidden?.list[1].name,
|
|
37
|
+
fontSize: hidden?.list[1].fontSize,
|
|
38
|
+
count: hidden?.list.length,
|
|
39
|
+
}, { hidden: true, name: 'My pwsh', fontSize: 14, count: 2 }, "turning pwsh off hides the profile and keeps the user's edits");
|
|
33
40
|
const oldForm = withPwshProfile({ profiles: [{ guid: 'a' }] }, true)?.profiles;
|
|
34
41
|
t.equal(oldForm.list.length, 2, 'the old array form of "profiles" works');
|
|
35
42
|
t.section('Windows Terminal settings.json on disk (JSONC, temp copy)');
|
|
@@ -42,7 +49,7 @@ export const personalizationSuite = {
|
|
|
42
49
|
t.write(path.join(data, 'tools', 'pwsh', 'pwsh.exe'), 'MZ');
|
|
43
50
|
syncPwshProfile(data, true);
|
|
44
51
|
const added = read();
|
|
45
|
-
t.equal(added.theme, 'light',
|
|
52
|
+
t.equal(added.theme, 'light', "once pwsh is installed the profile is added and the user's settings are kept");
|
|
46
53
|
t.equal(added.profiles.list.map((p) => p.guid), ['{x}', PWSH_PROFILE_GUID], 'the profile is added after the existing ones');
|
|
47
54
|
syncPwshProfile(data, false);
|
|
48
55
|
t.equal(read().profiles.list[1].hidden, true, 'the profile is hidden when pwsh is turned off');
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import type { Suite } from './suite.js';
|
|
1
|
+
import type { Suite } from './support/suite.js';
|
|
2
2
|
export declare const projectsSuite: Suite;
|
|
@@ -3,33 +3,37 @@
|
|
|
3
3
|
// environment, history sync and the repo guard for every project. Offline: temp folders only.
|
|
4
4
|
import fs from 'node:fs';
|
|
5
5
|
import path from 'node:path';
|
|
6
|
-
import {
|
|
7
|
-
import { checkJoin, protectionsOf } from '../core/
|
|
8
|
-
import { sessionsFirstIn } from '../host/channel.js';
|
|
9
|
-
import { buildWsb } from '../host/launch/
|
|
10
|
-
import { projectSpec, joinRunning } from '../host/
|
|
11
|
-
import { allProjectsToMap,
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
6
|
+
import { LocalOverridesSchema } from '../core/schema/index.js';
|
|
7
|
+
import { allowStorePath, checkJoin, describeMissing, missingAtBoot, missingTip, nothingMissing, protectionsOf, saveAllowed, } from '../core/local-config/index.js';
|
|
8
|
+
import { sessionsFirstIn } from '../host/channel/index.js';
|
|
9
|
+
import { buildWsb } from '../host/launch/index.js';
|
|
10
|
+
import { projectSpec, joinRunning } from '../host/projects/index.js';
|
|
11
|
+
import { allProjectsToMap, KnownProjects } from '../host/projects/index.js';
|
|
12
|
+
import { NeedsRestart, projectMapper } from '../host/projects/index.js';
|
|
13
|
+
import { parseWsbBoot, ProjectRegistry } from '../host/projects/index.js';
|
|
14
|
+
import { RepoGuardStore } from '../host/guard/index.js';
|
|
15
|
+
import { findWsb, parseCommands, parseIp, parseList, parseVersion } from '../host/sandbox/index.js';
|
|
16
|
+
import { baseEnvFor } from '../guest/boot/project-env.js';
|
|
17
|
+
import { guestDirFor, hostDirFor, hubName, insideProjects, isBelow, isWithin, planProjectMappings, projectForGuestDir, projectForHostDir, PROJECTS_GUEST, rootGuestDir, } from '../shared/paths/index.js';
|
|
18
|
+
import { GuestRequestSchema, ProjectSpecSchema } from '../shared/channel/index.js';
|
|
19
|
+
import { projectFolderName } from '../shared/paths/index.js';
|
|
20
|
+
import { syncHistoryOut } from '../sync/index.js';
|
|
19
21
|
import { validateOptions, validateProjectsArgs } from '../cli/validate.js';
|
|
20
22
|
import { parseCli, parseSessionWant } from '../cli/args.js';
|
|
21
23
|
import { candidateFolders, severalAgentsArgv } from '../cli/menu/index.js';
|
|
22
|
-
import { generateSandbox } from '../host/
|
|
24
|
+
import { generateSandbox } from '../host/launch/index.js';
|
|
23
25
|
import { askedWhen } from '../cli/manifest.js';
|
|
24
|
-
import { describeSessions } from '../cli/commands/
|
|
26
|
+
import { describeSessions } from '../cli/commands/projects/index.js';
|
|
25
27
|
/** The error `fn` throws, or null. */
|
|
26
|
-
const caught = (fn) => {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
28
|
+
const caught = (fn) => {
|
|
29
|
+
try {
|
|
30
|
+
fn();
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
catch (e) {
|
|
34
|
+
return e;
|
|
35
|
+
}
|
|
36
|
+
};
|
|
33
37
|
export const projectsSuite = {
|
|
34
38
|
name: 'projects',
|
|
35
39
|
title: 'several projects in one sandbox (paths, joining, policy, specs, --session)',
|
|
@@ -41,7 +45,10 @@ export const projectsSuite = {
|
|
|
41
45
|
t.equal(hubName('F:\\Code\\api', ['API', 'api-2']), 'api-3', 'project ids are unique (case-insensitive)');
|
|
42
46
|
t.equal(hubName('F:\\Code\\...', []), 'project', 'project ids are never empty');
|
|
43
47
|
t.equal(hubName('F:\\' + 'x'.repeat(80), []).length, 48, 'project ids are capped at 48 characters');
|
|
44
|
-
const projects = [
|
|
48
|
+
const projects = [
|
|
49
|
+
{ host: 'F:\\Code', guest: 'C:\\Projects\\Code' },
|
|
50
|
+
{ host: 'F:\\Code\\api', guest: 'C:\\Projects\\api' },
|
|
51
|
+
];
|
|
45
52
|
t.equal(projectForHostDir(projects, 'f:\\code\\api\\src')?.guest, 'C:\\Projects\\api', 'the most specific mapped folder wins');
|
|
46
53
|
t.equal(projectForHostDir(projects, 'F:\\Code\\web')?.guest, 'C:\\Projects\\Code', 'a folder inside a mapped folder belongs to it');
|
|
47
54
|
t.equal(projectForHostDir(projects, 'F:\\Other'), null, 'unrelated folders belong to no project');
|
|
@@ -57,25 +64,32 @@ export const projectsSuite = {
|
|
|
57
64
|
t.check(isBelow('C:\\a', 'C:\\a\\b') && !isBelow('C:\\a', 'C:\\a'), 'isBelow is strict');
|
|
58
65
|
const plan = planProjectMappings(['F:\\Code', 'E:\\Work\\Code', 'C:\\Users\\me\\src'], ['D:\\x\\api', 'D:\\y\\api'], false);
|
|
59
66
|
t.equal(plan.roots.map((r) => r.guest), ['C:\\Projects\\Code', 'C:\\Projects\\Code-2', 'C:\\Projects\\src'], 'roots get unique C:\\Projects\\<name> folders');
|
|
60
|
-
t.equal(plan.projects.map((p) => p.guest), ['C:\\
|
|
67
|
+
t.equal(plan.projects.map((p) => p.guest), ['C:\\Workspace\\api', 'C:\\Workspace\\api-2'], 'projects mapped on their own get unique C:\\Workspace\\<name> folders (where they are as the launch folder)');
|
|
68
|
+
t.equal(planProjectMappings([], ['D:\\x\\app'], false, ['C:\\Workspace\\app']).projects[0].guest, 'C:\\Workspace\\app-2', "a project mapped on its own never lands on the launch folder's place");
|
|
69
|
+
t.equal(planProjectMappings(['F:\\Code'], ['D:\\x\\api'], true).projects[0].guest, 'D:\\x\\api', 'with "mirror" a project mapped on its own appears at its PC path, as it would as the launch folder');
|
|
70
|
+
t.equal(rootGuestDir(['F:\\Code'], false, 'F:\\Code\\web\\src'), 'C:\\Projects\\Code\\web\\src', "a folder inside a root is placed under the root's guest folder");
|
|
71
|
+
t.equal(rootGuestDir(['F:\\Code'], false, 'F:\\Other'), null, 'a folder in no root has no root place');
|
|
61
72
|
const mirror = planProjectMappings(['F:\\Code', 'C:\\Users\\me\\src'], [], true);
|
|
62
73
|
t.equal(mirror.roots.map((r) => r.guest), ['F:\\Code', 'C:\\Projects\\src'], 'with "mirror" a root appears at its PC path when the sandbox can show it there (C:\\Users\\... cannot)');
|
|
63
74
|
t.section('projects: tighten-only protections when joining a running sandbox');
|
|
64
75
|
const base = protectionsOf(f.baseConfig);
|
|
65
76
|
const same = checkJoin(base, base);
|
|
66
77
|
t.equal({ stricter: same.stricter, looser: same.looser }, { stricter: [], looser: [] }, 'the same settings join without notes');
|
|
67
|
-
const readonlyGit = protectionsOf({
|
|
78
|
+
const readonlyGit = protectionsOf({
|
|
79
|
+
...f.baseConfig,
|
|
80
|
+
provisioning: { ...f.baseConfig.provisioning, git: { ...f.baseConfig.provisioning.git, access: 'readonly' } },
|
|
81
|
+
});
|
|
68
82
|
t.check(checkJoin(base, readonlyGit).stricter.some((s) => s.startsWith('provisioning.git.access')), 'a project needing stricter git access than the running sandbox is refused (git access is machine-wide)');
|
|
69
83
|
const loosening = checkJoin(readonlyGit, base);
|
|
70
84
|
t.equal(loosening.stricter.length, 0, 'a project asking for less git access is not refused...');
|
|
71
|
-
t.check(loosening.looser.some((s) => s.includes('provisioning.git.access stays "readonly"')),
|
|
85
|
+
t.check(loosening.looser.some((s) => s.includes('provisioning.git.access stays "readonly"')), "... it gets the sandbox's stricter value, with a note: never loosened", JSON.stringify(loosening.looser));
|
|
72
86
|
const offline = protectionsOf({ ...f.baseConfig, sandbox: { ...f.baseConfig.sandbox, networking: false } });
|
|
73
87
|
t.check(checkJoin(base, offline).stricter.some((s) => s.startsWith('sandbox.networking')), 'networking off is stricter than a sandbox with networking');
|
|
74
88
|
t.check(checkJoin(offline, base).looser.some((s) => s.startsWith('sandbox.networking')), 'networking on is looser than an offline sandbox');
|
|
75
89
|
const readOnly = protectionsOf({ ...f.baseConfig, readOnly: true });
|
|
76
90
|
t.check(checkJoin(readOnly, readOnly).stricter.some((s) => s.startsWith('readOnly')), 'a read-only project cannot join (other projects are mapped read/write), even when the launch folder was read-only');
|
|
77
|
-
t.check(!
|
|
78
|
-
t.check(!
|
|
91
|
+
t.check(!LocalOverridesSchema.safeParse({ projects: { roots: ['C:\\'] } }).success, "a project's .sandbox-config.json can never set projects.roots (they map folders of this PC)");
|
|
92
|
+
t.check(!LocalOverridesSchema.safeParse({ projects: { all: true } }).success, "a project's .sandbox-config.json can never set projects.all");
|
|
79
93
|
// A project file that loosens git access is clamped by keepStrictest first, then joins without being refused.
|
|
80
94
|
const strictUser = structuredClone(f.baseConfig);
|
|
81
95
|
strictUser.provisioning.git.access = 'readonly';
|
|
@@ -94,24 +108,35 @@ export const projectsSuite = {
|
|
|
94
108
|
const root = t.at('proj-root');
|
|
95
109
|
const inRoot = t.dir('proj-root', 'web');
|
|
96
110
|
const outside = t.dir('proj-outside');
|
|
97
|
-
const primary =
|
|
98
|
-
|
|
111
|
+
const primary = new ProjectRegistry(storage).start({
|
|
112
|
+
launchId: '1700000000000-abcdef',
|
|
113
|
+
protections: base,
|
|
114
|
+
primary: { host: f.workA, guest: 'C:\\Workspace\\work-a' },
|
|
115
|
+
roots: [{ host: root, guest: 'C:\\Projects\\proj-root' }],
|
|
116
|
+
boot: [{ host: f.workB, guest: 'C:\\Projects\\work-b' }],
|
|
117
|
+
});
|
|
118
|
+
const registry = new ProjectRegistry(storage).read();
|
|
99
119
|
t.check(primary.primary, 'at launch the launch folder is the primary project');
|
|
100
120
|
t.equal(registry?.projects.length, 2, 'at launch the registry holds the launch folder and the projects mapped with it');
|
|
101
121
|
t.equal({ mechanism: registry?.projects[1].mechanism, name: registry?.projects[1].name }, { mechanism: 'boot', name: 'work-b' }, 'a project mapped at boot is registered by its mechanism and name');
|
|
102
|
-
t.equal(
|
|
103
|
-
t.equal(
|
|
104
|
-
t.equal(
|
|
122
|
+
t.equal(new ProjectRegistry(storage).here(path.join(f.workA, 'src'))?.guestDir, 'C:\\Workspace\\work-a\\src', 'projectHere: a folder inside the launch folder');
|
|
123
|
+
t.equal(new ProjectRegistry(storage).here(f.workB)?.project.mechanism, 'boot', 'projectHere: a project mapped at boot');
|
|
124
|
+
t.equal(new ProjectRegistry(storage).here(outside), null, 'projectHere: a folder in no project');
|
|
105
125
|
const noWsb = projectMapper({ storageRoot: storage, packageRoot: f.install, wsbShare: true, detect: () => null });
|
|
106
126
|
const web = noWsb.register(inRoot);
|
|
107
127
|
t.equal({ mechanism: web.mechanism, guest: web.guest }, { mechanism: 'root', guest: 'C:\\Projects\\proj-root\\web' }, 'a folder inside a root joins at once (also one created after boot)');
|
|
108
128
|
t.equal(noWsb.register(inRoot).name, web.name, 'registering the same folder again gives the same project');
|
|
109
|
-
t.equal(
|
|
129
|
+
t.equal(new ProjectRegistry(storage).read()?.projects.filter((p) => p.host === inRoot).length, 1, 'a folder is registered once');
|
|
110
130
|
const needs = caught(() => noWsb.register(outside));
|
|
111
131
|
t.check(needs instanceof NeedsRestart && needs.reason.includes('wsb share needs Windows 11 24H2'), 'a folder outside every root without the Windows Sandbox CLI needs a restart (and says why)');
|
|
112
132
|
const shareOff = caught(() => projectMapper({ storageRoot: storage, packageRoot: f.install, wsbShare: false }).register(outside));
|
|
113
133
|
t.check(shareOff instanceof NeedsRestart && shareOff.reason.includes('projects.wsbShare'), 'projects.wsbShare off goes straight to the restart offer');
|
|
114
|
-
const fakeWsb = {
|
|
134
|
+
const fakeWsb = {
|
|
135
|
+
exe: t.at('no-such-wsb.exe'),
|
|
136
|
+
version: '0.1.0',
|
|
137
|
+
commands: ['share', 'list'],
|
|
138
|
+
has: (c) => c === 'share' || c === 'list',
|
|
139
|
+
};
|
|
115
140
|
const listFails = caught(() => projectMapper({ storageRoot: storage, packageRoot: f.install, wsbShare: true, detect: () => fakeWsb }).register(outside));
|
|
116
141
|
t.check(listFails instanceof NeedsRestart && listFails.reason.includes('wsb share could not find the running sandbox'), 'when wsb cannot tell which sandbox is ours, it falls back to the restart offer with the reason');
|
|
117
142
|
await t.throws(() => noWsb.register(storage), 'cannot be the workspace', 'joining uses the launch-folder safety checks: not the storage folder');
|
|
@@ -123,17 +148,40 @@ export const projectsSuite = {
|
|
|
123
148
|
const webRun = await f.run({ cwd: inRoot, trustConfig: true });
|
|
124
149
|
const joined = await join(inRoot, resolveFor(webRun));
|
|
125
150
|
t.equal(joined.spec?.workspace, 'C:\\Projects\\proj-root\\web', 'joining a project builds a spec with its guest folder...');
|
|
126
|
-
t.check(
|
|
127
|
-
t.check(
|
|
151
|
+
t.check(ProjectSpecSchema.safeParse(joined.spec).success && joined.spec?.harnesses.claude !== undefined, '... that is valid and carries the agent');
|
|
152
|
+
t.check(new KnownProjects(storage).list().some((k) => k.host === inRoot), 'joined projects are remembered (projects.all, sandbox projects)');
|
|
128
153
|
const launchFolder = await join(path.join(f.workA, 'sub'), () => Promise.reject(new Error('must not resolve')));
|
|
129
154
|
t.equal(launchFolder.spec, null, 'the launch folder (and below) needs no spec: its sessions use the boot environment');
|
|
130
|
-
await t.throws(() => join(tightDir, resolveFor(tight)), 'stricter
|
|
131
|
-
t.check(
|
|
155
|
+
await t.throws(() => join(tightDir, resolveFor(tight)), 'stricter than the running sandbox', 'a project whose .sandbox-config.json tightens git access beyond the running sandbox is refused without your consent, with the reason');
|
|
156
|
+
t.check(new ProjectRegistry(storage).read()?.projects.every((p) => p.host !== tightDir) === true, 'a refused project is not registered');
|
|
157
|
+
let asked = [];
|
|
158
|
+
const agreed = await t.thrownMessage(() => joinRunning({
|
|
159
|
+
storageRoot: storage,
|
|
160
|
+
dataPath: data,
|
|
161
|
+
packageRoot: f.install,
|
|
162
|
+
hostDir: tightDir,
|
|
163
|
+
wsbShare: false,
|
|
164
|
+
resolve: resolveFor(tight),
|
|
165
|
+
acceptStricter: async (_name, stricter) => {
|
|
166
|
+
asked = stricter;
|
|
167
|
+
return true;
|
|
168
|
+
},
|
|
169
|
+
}));
|
|
170
|
+
t.check(asked.some((s) => s.startsWith('provisioning.git.access')) &&
|
|
171
|
+
!agreed.includes('stricter than the running sandbox'), 'with your consent it is not refused for its stricter settings (it goes on to joining: here a restart, as its folder is outside every root)', agreed);
|
|
132
172
|
const outsideRun = await f.run({ cwd: outside });
|
|
133
173
|
await t.throws(() => join(outside, resolveFor(outsideRun)), 'projects.wsbShare', 'a folder that cannot be shown lets NeedsRestart reach the caller');
|
|
134
174
|
t.section('projects: the spec and request the guest gets');
|
|
135
175
|
const spec = projectSpec(webRun, web, false);
|
|
136
|
-
const sessionRequest = (extra) =>
|
|
176
|
+
const sessionRequest = (extra) => GuestRequestSchema.safeParse({
|
|
177
|
+
kind: 'session',
|
|
178
|
+
id: 'r1',
|
|
179
|
+
harness: 'claude',
|
|
180
|
+
args: [],
|
|
181
|
+
cwd: spec.workspace,
|
|
182
|
+
createdAt: new Date().toISOString(),
|
|
183
|
+
...extra,
|
|
184
|
+
});
|
|
137
185
|
t.check(sessionRequest({ project: spec }).success, 'a session request carries a project spec');
|
|
138
186
|
t.check(sessionRequest({ project: spec, harnessSpec: f.baseConfig.harnesses.codex }).success, 'a session request carries an agent definition');
|
|
139
187
|
t.check(!sessionRequest({ project: { ...spec, name: '..\\evil' } }).success, 'specs are validated: project ids are file-name safe');
|
|
@@ -142,29 +190,57 @@ export const projectsSuite = {
|
|
|
142
190
|
t.check(!sessionRequest({ project: { ...spec, databases: manyDatabases } }).success, 'specs are validated: lists are capped');
|
|
143
191
|
const manyAgents = Object.fromEntries(Array.from({ length: 9 }, (_, i) => ['a' + i, f.baseConfig.harnesses.codex]));
|
|
144
192
|
t.check(!sessionRequest({ project: { ...spec, harnesses: manyAgents } }).success, 'at most 8 agent definitions in one spec');
|
|
145
|
-
t.check(
|
|
146
|
-
t.check(!
|
|
147
|
-
t.check(
|
|
148
|
-
|
|
193
|
+
t.check(GuestRequestSchema.safeParse({ kind: 'project', id: 'p1', project: spec, createdAt: 'x' }).success, '"project" requests (set up without an agent) carry a spec');
|
|
194
|
+
t.check(!GuestRequestSchema.safeParse({ kind: 'project', id: 'p1', createdAt: 'x' }).success, '"project" requests need a spec');
|
|
195
|
+
t.check(GuestRequestSchema.safeParse({ kind: 'restart', id: 'x', harness: null, cwd: 'C:\\Projects\\a', createdAt: 'x' })
|
|
196
|
+
.success, "restart can be scoped to one project's folder");
|
|
197
|
+
t.check(GuestRequestSchema.safeParse({ kind: 'restart', id: 'x', harness: null, createdAt: 'x' }).success, 'restart still works without a folder');
|
|
149
198
|
t.section('projects: which projects are mapped at boot');
|
|
150
|
-
const toMap = allProjectsToMap(['C:\\a', 'C:\\a\\b', 'C:\\work-a\\x', 'C:\\r\\p', 'C:\\ex\\y', 'C:\\gone'], {
|
|
151
|
-
|
|
199
|
+
const toMap = allProjectsToMap(['C:\\a', 'C:\\a\\b', 'C:\\work-a\\x', 'C:\\r\\p', 'C:\\ex\\y', 'C:\\gone'], {
|
|
200
|
+
primary: 'C:\\work-a',
|
|
201
|
+
roots: ['C:\\r'],
|
|
202
|
+
exclude: ['C:\\ex'],
|
|
203
|
+
exists: (p) => p !== 'C:\\gone',
|
|
204
|
+
});
|
|
205
|
+
t.equal(toMap, ['C:\\a'], "projects.all: known projects except excluded, missing, nested, the launch folder's and the roots'");
|
|
152
206
|
const rootConfig = structuredClone(f.baseConfig);
|
|
153
207
|
rootConfig.projects = { ...rootConfig.projects, roots: [root, t.at('no-such-root')], all: true };
|
|
154
|
-
|
|
208
|
+
new KnownProjects(f.baseConfig.storage.root).remember(outside);
|
|
155
209
|
const gen = f.generate(await f.run({}, rootConfig));
|
|
156
210
|
const session = f.readJson(gen.sessionPath);
|
|
157
211
|
const wsb = fs.readFileSync(gen.wsbPath, 'utf8');
|
|
158
212
|
t.equal(gen.projects.roots.map((r) => r.guest), ['C:\\Projects\\proj-root'], 'roots are mapped as C:\\Projects\\<name>');
|
|
159
213
|
t.check(gen.projects.notes.some((n) => n.includes('no-such-root')), 'a missing root is skipped with a note', JSON.stringify(gen.projects.notes));
|
|
160
214
|
t.check(gen.projects.projects.some((p) => p.host === outside), 'projects.all maps the known projects too');
|
|
161
|
-
t.includes(wsb, '<HostFolder>' +
|
|
162
|
-
|
|
215
|
+
t.includes(wsb, '<HostFolder>' +
|
|
216
|
+
root +
|
|
217
|
+
'</HostFolder><SandboxFolder>C:\\Projects\\proj-root</SandboxFolder><ReadOnly>false</ReadOnly>', 'roots are mapped read/write in the .wsb');
|
|
218
|
+
t.equal({ projectsDir: session.projectsDir, roots: session.roots, projectId: session.projectId }, {
|
|
219
|
+
projectsDir: PROJECTS_GUEST,
|
|
220
|
+
roots: ['C:\\Projects\\proj-root', 'C:\\Workspace\\proj-outside'],
|
|
221
|
+
projectId: 'work-a',
|
|
222
|
+
}, 'session.json tells the guest where other projects can be');
|
|
223
|
+
// The same project is at the same place whether it started the sandbox or joined one another project started.
|
|
224
|
+
const fromRoot = f.generate(await f.run({ cwd: inRoot }, rootConfig));
|
|
225
|
+
const joinedAt = guestDirFor(gen.projects.roots[0], inRoot);
|
|
226
|
+
t.equal([f.readJson(fromRoot.sessionPath).workspace, joinedAt], ['C:\\Projects\\proj-root\\web', 'C:\\Projects\\proj-root\\web'], 'a project in a root: the same guest folder as the launch folder and when another project started the sandbox');
|
|
227
|
+
t.check(!fromRoot.mappings.some((m) => m.host.toLowerCase() === inRoot.toLowerCase()), 'a launch folder inside a root is shown by the root (no second mapping of it)');
|
|
228
|
+
t.includes(fs.readFileSync(path.join(fromRoot.launchPath, 'env.cmd'), 'utf8'), 'AGENT_WORKSPACE=C:\\Projects\\proj-root\\web', 'env.cmd: AGENT_WORKSPACE follows');
|
|
229
|
+
const asLaunch = f.readJson(f.generate(await f.run({ cwd: outside })).sessionPath).workspace;
|
|
230
|
+
t.equal([asLaunch, gen.projects.projects.find((p) => p.host === outside)?.guest], ['C:\\Workspace\\proj-outside', 'C:\\Workspace\\proj-outside'], 'a project outside the roots: the same guest folder as the launch folder and when mapped at boot by another');
|
|
231
|
+
const mirrorRoot = structuredClone(rootConfig);
|
|
232
|
+
mirrorRoot.guestWorkspace = 'mirror';
|
|
233
|
+
t.equal(f.readJson(f.generate(await f.run({ cwd: inRoot }, mirrorRoot)).sessionPath).workspace, rootGuestDir([root], true, inRoot), 'with "mirror" a launch folder inside a root is where the root shows it (no overlapping mappings)');
|
|
234
|
+
const filtered = structuredClone(rootConfig);
|
|
235
|
+
filtered.workspaceFilter = { ...filtered.workspaceFilter, enabled: true };
|
|
236
|
+
const filteredRun = await f.run({ cwd: inRoot }, filtered);
|
|
237
|
+
t.equal(filteredRun.config.guestWorkspace, 'C:\\Workspace\\web', 'workspaceFilter: a launch folder inside a root keeps its own (filtered) mapping');
|
|
238
|
+
t.check(filteredRun.notes.some((n) => n.includes('C:\\Projects\\proj-root\\web')), 'and a note says where it is when another project starts the sandbox', JSON.stringify(filteredRun.notes));
|
|
163
239
|
const badRoot = structuredClone(f.baseConfig);
|
|
164
240
|
badRoot.projects = { ...badRoot.projects, roots: [f.baseConfig.storage.root] };
|
|
165
241
|
await t.throws(async () => f.generate(await f.run({}, badRoot)), 'projects.roots', 'a root that would expose the storage folder is refused');
|
|
166
|
-
t.check(
|
|
167
|
-
t.check(!
|
|
242
|
+
t.check(new KnownProjects(f.baseConfig.storage.root).forget(outside), '`sandbox projects remove` forgets a project...');
|
|
243
|
+
t.check(!new KnownProjects(f.baseConfig.storage.root).list().some((k) => k.host === outside), '... so it is no longer known (its folder is untouched)');
|
|
168
244
|
t.includes(buildWsb(f.baseConfig, 4096, []), '<MappedFolders></MappedFolders>', 'no projects: nothing extra mapped');
|
|
169
245
|
t.section('projects: repo guard for every project the sandbox can write');
|
|
170
246
|
const guardData = t.at('guard-data');
|
|
@@ -172,13 +248,13 @@ export const projectsSuite = {
|
|
|
172
248
|
const old = path.join(rootG, 'old');
|
|
173
249
|
t.write(path.join(old, '.git', 'hooks', 'pre-commit'), 'mine');
|
|
174
250
|
t.write(path.join(old, '.git', 'config'), '[core]\n\tbare = false\n');
|
|
175
|
-
|
|
251
|
+
new RepoGuardStore(guardData).save(f.workA, [], [rootG]);
|
|
176
252
|
t.write(path.join(old, '.git', 'hooks', 'post-checkout'), 'planted');
|
|
177
253
|
const fresh = path.join(rootG, 'created-later');
|
|
178
254
|
t.write(path.join(fresh, '.git', 'hooks', 'pre-push'), 'planted');
|
|
179
255
|
t.write(path.join(fresh, '.git', 'config'), '[core]\n\tfsmonitor = evil.exe\n\tbare = false\n');
|
|
180
256
|
t.write(path.join(fresh, 'node.exe'), 'planted');
|
|
181
|
-
const found =
|
|
257
|
+
const found = new RepoGuardStore(guardData).check();
|
|
182
258
|
t.check(fs.existsSync(path.join(old, '.git', 'hooks', 'pre-commit')), 'a hook that was there before the sandbox ran stays');
|
|
183
259
|
t.check(!fs.existsSync(path.join(old, '.git', 'hooks', 'post-checkout')), 'a hook added inside the sandbox to a project in a root is quarantined');
|
|
184
260
|
t.check(!fs.existsSync(path.join(fresh, '.git', 'hooks', 'pre-push')), 'a project that appeared in a root after the start has its planted hooks removed');
|
|
@@ -190,17 +266,61 @@ export const projectsSuite = {
|
|
|
190
266
|
const guestClaude = t.at('hist-guest');
|
|
191
267
|
const bHost = t.at('hist-b');
|
|
192
268
|
t.write(path.join(guestClaude, 'projects', projectFolderName('C:\\Projects\\hist-b'), 's.jsonl'), JSON.stringify({ cwd: 'C:\\Projects\\hist-b\\src' }) + '\n');
|
|
193
|
-
syncHistoryOut({
|
|
269
|
+
syncHistoryOut({
|
|
270
|
+
hostClaudeDir: hostClaude,
|
|
271
|
+
guestClaudeDir: guestClaude,
|
|
272
|
+
hostWorkspace: f.workA,
|
|
273
|
+
guestWorkspace: 'C:\\Workspace\\work-a',
|
|
274
|
+
extra: [{ hostWorkspace: bHost, guestWorkspace: 'C:\\Projects\\hist-b' }],
|
|
275
|
+
});
|
|
194
276
|
const back = path.join(hostClaude, 'projects', projectFolderName(bHost), 's.jsonl');
|
|
195
|
-
t.check(fs.existsSync(back),
|
|
196
|
-
t.includes(fs.existsSync(back) ? fs.readFileSync(back, 'utf8') : '', JSON.stringify(bHost + '\\src').slice(1, -1),
|
|
197
|
-
const env = baseEnvFor({ basePath: 'C:\\Windows', toolVars: ['NVM_HOME', 'CARGO_HOME'], steps: {}, summary: [], lan: 'blocked' }, {
|
|
198
|
-
|
|
277
|
+
t.check(fs.existsSync(back), "a joined project's history goes back to ITS folder on this PC");
|
|
278
|
+
t.includes(fs.existsSync(back) ? fs.readFileSync(back, 'utf8') : '', JSON.stringify(bHost + '\\src').slice(1, -1), "a joined project's history paths are translated");
|
|
279
|
+
const env = baseEnvFor({ basePath: 'C:\\Windows', toolVars: ['NVM_HOME', 'CARGO_HOME'], steps: {}, summary: [], lan: 'blocked' }, {
|
|
280
|
+
Path: 'C:\\tools\\a;C:\\Windows',
|
|
281
|
+
NVM_HOME: 'x',
|
|
282
|
+
CARGO_HOME: 'y',
|
|
283
|
+
CARGO_TARGET_DIR: 'C:\\Workspace\\a\\target',
|
|
284
|
+
AGENT_WORKSPACE: 'C:\\Workspace\\a',
|
|
285
|
+
TEMP: 'C:\\t',
|
|
286
|
+
});
|
|
287
|
+
t.equal({
|
|
288
|
+
PATH: env.PATH,
|
|
289
|
+
Path: env.Path,
|
|
290
|
+
NVM_HOME: env.NVM_HOME,
|
|
291
|
+
CARGO_TARGET_DIR: env.CARGO_TARGET_DIR,
|
|
292
|
+
AGENT_WORKSPACE: env.AGENT_WORKSPACE,
|
|
293
|
+
TEMP: env.TEMP,
|
|
294
|
+
}, {
|
|
295
|
+
PATH: 'C:\\Windows',
|
|
296
|
+
Path: undefined,
|
|
297
|
+
NVM_HOME: undefined,
|
|
298
|
+
CARGO_TARGET_DIR: undefined,
|
|
299
|
+
AGENT_WORKSPACE: undefined,
|
|
300
|
+
TEMP: 'C:\\t',
|
|
301
|
+
}, "a joined project starts from the boot's base environment: none of the first project's tools, workspace or target folder");
|
|
199
302
|
t.section('projects: commands');
|
|
200
|
-
const status = (id, cwd, startedAt) => ({
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
303
|
+
const status = (id, cwd, startedAt) => ({
|
|
304
|
+
id,
|
|
305
|
+
launchId: 'l',
|
|
306
|
+
harness: 'claude',
|
|
307
|
+
cwd,
|
|
308
|
+
phase: 'running',
|
|
309
|
+
message: '',
|
|
310
|
+
updatedAt: startedAt,
|
|
311
|
+
startedAt,
|
|
312
|
+
});
|
|
313
|
+
const sessions = [
|
|
314
|
+
status('a1', 'C:\\Workspace\\a', '1'),
|
|
315
|
+
status('b1', 'C:\\Projects\\b', '2'),
|
|
316
|
+
status('a2', 'C:\\Workspace\\a\\x', '3'),
|
|
317
|
+
status('b2', 'C:\\Projects\\b\\y', '4'),
|
|
318
|
+
];
|
|
319
|
+
t.equal(sessionsFirstIn(sessions, 'C:\\Projects\\b').map((x) => x.id), ['b2', 'b1', 'a2', 'a1'], "attach and sessions put this project's sessions first, newest first");
|
|
320
|
+
t.equal(describeSessions([
|
|
321
|
+
{ harness: 'claude', cwd: 'C:\\Workspace\\api', project: 'api' },
|
|
322
|
+
{ harness: 'codex', cwd: 'C:\\Projects\\web' },
|
|
323
|
+
]), '2 sessions (claude in api, codex in web)', 'the restart offer lists the sessions that would end');
|
|
204
324
|
await t.throws(() => validateProjectsArgs(['bogus']), 'projects action', '`sandbox projects` rejects an unknown action');
|
|
205
325
|
await t.throws(() => validateProjectsArgs(['add']), 'Which folder', '`sandbox projects add` needs a folder');
|
|
206
326
|
await t.throws(() => validateProjectsArgs(['all', 'maybe']), 'on', '`sandbox projects all` needs on or off');
|
|
@@ -208,7 +328,10 @@ export const projectsSuite = {
|
|
|
208
328
|
validateProjectsArgs([]);
|
|
209
329
|
validateProjectsArgs(['roots']);
|
|
210
330
|
validateProjectsArgs(['all', 'on']);
|
|
211
|
-
t.check(askedWhen(['add', 'remove'], 'add') &&
|
|
331
|
+
t.check(askedWhen(['add', 'remove'], 'add') &&
|
|
332
|
+
!askedWhen(['add'], 'list') &&
|
|
333
|
+
askedWhen(undefined, 'x') &&
|
|
334
|
+
askedWhen('save', 'save'), 'the menu asks an argument only for the actions it belongs to');
|
|
212
335
|
t.section('projects: several sessions at once (--session agent@folder)');
|
|
213
336
|
const want = parseSessionWant('claude@C:\\code\\a@b', 'C:\\here');
|
|
214
337
|
t.equal({ harness: want.harness, folder: want.folder }, { harness: 'claude', folder: 'C:\\code\\a@b' }, '--session: the first @ splits agent from folder');
|
|
@@ -216,26 +339,167 @@ export const projectsSuite = {
|
|
|
216
339
|
t.equal(parseSessionWant('gemini@sub', 'C:\\here').folder, 'C:\\here\\sub', '--session: relative folders become absolute');
|
|
217
340
|
await t.throws(() => parseSessionWant('@C:\\x'), 'names no agent', '--session without an agent is refused');
|
|
218
341
|
const own = parseSessionWant('codex@C:\\code\\web|--model o3 "two words"', 'C:\\here');
|
|
219
|
-
t.equal({ harness: own.harness, folder: own.folder, args: own.args }, { harness: 'codex', folder: 'C:\\code\\web', args: ['--model', 'o3', 'two words'] },
|
|
342
|
+
t.equal({ harness: own.harness, folder: own.folder, args: own.args }, { harness: 'codex', folder: 'C:\\code\\web', args: ['--model', 'o3', 'two words'] }, "--session: after | come that agent's own arguments (quotes keep words together)");
|
|
220
343
|
t.equal(parseSessionWant('claude@C:\\x').args, undefined, '--session: no | means no own arguments');
|
|
221
|
-
const both = parseCli([
|
|
344
|
+
const both = parseCli([
|
|
345
|
+
'launch',
|
|
346
|
+
'--session',
|
|
347
|
+
'claude@C:\\a|--continue',
|
|
348
|
+
'--session',
|
|
349
|
+
'codex@C:\\b',
|
|
350
|
+
'--',
|
|
351
|
+
'--verbose',
|
|
352
|
+
]);
|
|
222
353
|
t.equal(both.passthrough, ['--verbose'], 'arguments after -- go to every session...');
|
|
223
354
|
t.equal(both.sessions.map((s) => s.args ?? []), [['--continue'], []], '... arguments after | only to that one');
|
|
224
|
-
const multi = parseCli([
|
|
225
|
-
|
|
226
|
-
|
|
355
|
+
const multi = parseCli([
|
|
356
|
+
'launch',
|
|
357
|
+
'--session',
|
|
358
|
+
'claude@' + f.workA,
|
|
359
|
+
'--session',
|
|
360
|
+
'codex@' + f.workB,
|
|
361
|
+
'--session',
|
|
362
|
+
'claude@' + f.workB,
|
|
363
|
+
'-t',
|
|
364
|
+
'--',
|
|
365
|
+
'--continue',
|
|
366
|
+
]);
|
|
367
|
+
t.equal({
|
|
368
|
+
command: multi.command,
|
|
369
|
+
sessions: multi.sessions.length,
|
|
370
|
+
terminal: multi.terminal,
|
|
371
|
+
second: multi.sessions[1].harness,
|
|
372
|
+
passthrough: multi.passthrough,
|
|
373
|
+
}, { command: 'launch', sessions: 3, terminal: true, second: 'codex', passthrough: ['--continue'] }, 'several --session options parse in order, with -t and agent arguments');
|
|
374
|
+
const validationContext = (options) => ({
|
|
375
|
+
packageRoot: f.install,
|
|
376
|
+
entry: '',
|
|
377
|
+
options,
|
|
378
|
+
loaded: { config: f.baseConfig, configPath: null, base: t.temp },
|
|
379
|
+
storageRoot: f.baseConfig.storage.root,
|
|
380
|
+
dataPath: t.at('vdata'),
|
|
381
|
+
});
|
|
227
382
|
await t.throws(() => validateOptions(validationContext(parseCli(['launch', '--session', 'claud@' + f.workA]))), 'Did you mean', 'an unknown agent in --session suggests the closest one');
|
|
228
383
|
await t.throws(() => validateOptions(validationContext(parseCli(['launch', '--session', 'claude@' + t.at('nope')]))), 'does not exist', 'a missing --session folder is refused before anything starts');
|
|
229
384
|
await t.throws(() => validateOptions(validationContext(parseCli(['launch', '--session', 'claude@' + f.workA, '--harness', 'codex']))), 'do not apply', '--session cannot be mixed with --harness/--workspace');
|
|
230
385
|
validateOptions(validationContext(multi));
|
|
231
|
-
t.equal(severalAgentsArgv([
|
|
386
|
+
t.equal(severalAgentsArgv([
|
|
387
|
+
{ harness: 'claude', folder: 'C:\\a' },
|
|
388
|
+
{ harness: 'codex', folder: 'C:\\b c' },
|
|
389
|
+
], { headless: true, attachFirst: true }).join(' '), 'launch --session claude@C:\\a --session codex@C:\\b c --headless -t', 'the menu builds the same command line (so repeat-last works)');
|
|
232
390
|
t.equal(candidateFolders(validationContext(parseCli(['launch'])), f.workA)[0], path.resolve(f.workA), 'the menu offers this folder first, then known projects and the folders in your roots');
|
|
233
|
-
const multiGen = generateSandbox({
|
|
391
|
+
const multiGen = generateSandbox({
|
|
392
|
+
packageRoot: t.packageRoot,
|
|
393
|
+
run: await f.run(),
|
|
394
|
+
harnessArgs: [],
|
|
395
|
+
probe: f.probe,
|
|
396
|
+
extraProjects: [f.workB, path.join(f.workA, 'sub'), f.workB],
|
|
397
|
+
autoSession: false,
|
|
398
|
+
});
|
|
234
399
|
const multiSession = f.readJson(multiGen.sessionPath);
|
|
235
400
|
const multiWsb = fs.readFileSync(multiGen.wsbPath, 'utf8');
|
|
236
|
-
t.equal(multiGen.projects.projects.map((p) => p.guest), ['C:\\
|
|
237
|
-
t.includes(multiWsb, '<HostFolder>' + f.workB + '</HostFolder><SandboxFolder>C:\\
|
|
401
|
+
t.equal(multiGen.projects.projects.map((p) => p.guest), ['C:\\Workspace\\work-b'], 'a multi-project launch maps every other project once (folders inside the launch folder and duplicates need nothing)');
|
|
402
|
+
t.includes(multiWsb, '<HostFolder>' + f.workB + '</HostFolder><SandboxFolder>C:\\Workspace\\work-b</SandboxFolder>', 'a multi-project launch maps the other project in the .wsb');
|
|
238
403
|
t.equal({ autoSession: multiSession.autoSession, workspaceHost: multiSession.workspaceHost }, { autoSession: false, workspaceHost: f.workA }, 'the boot provisions the launch folder only; the host then opens every session (each project set up on demand, in parallel)');
|
|
404
|
+
t.section('projects: what a joining project wants at boot (vGPU, memory, its mappings)');
|
|
405
|
+
// A games project: its approved file asks for vGPU (you allowed it for this project) and maps a folder of its own.
|
|
406
|
+
const games = t.dir('proj-games');
|
|
407
|
+
t.dir('proj-games', 'assets');
|
|
408
|
+
f.writeLocal(games, {
|
|
409
|
+
sandbox: { vGpu: true },
|
|
410
|
+
mappings: [{ host: 'assets', guest: 'F:\\GameAssets', readOnly: true }],
|
|
411
|
+
});
|
|
412
|
+
saveAllowed(allowStorePath(f.baseConfig.storage.root), path.join(games, '.sandbox-config.json'), 'sandbox.vGpu', true, true);
|
|
413
|
+
const gamesRun = await f.run({ cwd: games, trustConfig: true });
|
|
414
|
+
t.equal(gamesRun.config.sandbox.vGpu, true, 'the vGPU you allowed for the project is in its effective config');
|
|
415
|
+
const launchedRun = await f.run();
|
|
416
|
+
const runningBoot = {
|
|
417
|
+
memoryMb: 8192,
|
|
418
|
+
mappings: [{ host: f.workA, guest: 'C:\\Workspace\\work-a', readOnly: false }],
|
|
419
|
+
};
|
|
420
|
+
const wanted = missingAtBoot(protectionsOf(launchedRun.config), runningBoot, gamesRun.config, fs.existsSync);
|
|
421
|
+
t.equal({ settings: wanted.settings, memoryMb: wanted.memoryMb, mappings: wanted.mappings.map((m) => m.guest) }, { settings: ['sandbox.vGpu'], memoryMb: null, mappings: ['F:\\GameAssets'] }, "missingAtBoot: vGPU and the project's folder are missing from a sandbox started without them (the missing optional mapping is no wish)");
|
|
422
|
+
const mappedMirror = missingAtBoot(protectionsOf(gamesRun.config), {
|
|
423
|
+
memoryMb: 8192,
|
|
424
|
+
mappings: [{ host: path.join(games, 'assets'), guest: 'C:\\Mirror\\F\\GameAssets', readOnly: true }],
|
|
425
|
+
}, gamesRun.config, fs.existsSync);
|
|
426
|
+
t.check(nothingMissing(mappedMirror), 'missingAtBoot: nothing missing when the sandbox has vGPU and the folder (F:\\x is C:\\Mirror\\F\\x in the .wsb)', JSON.stringify(mappedMirror));
|
|
427
|
+
const bigger = structuredClone(launchedRun.config);
|
|
428
|
+
bigger.sandbox.memoryMb = 16384;
|
|
429
|
+
t.equal(missingAtBoot(protectionsOf(launchedRun.config), runningBoot, bigger).memoryMb, 16384, 'missingAtBoot: a larger fixed memory size is missing too');
|
|
430
|
+
const twoFolders = {
|
|
431
|
+
settings: ['sandbox.vGpu'],
|
|
432
|
+
memoryMb: null,
|
|
433
|
+
mappings: [
|
|
434
|
+
{ host: 'C:\\Steam\\common', guest: 'C:\\Steam', readOnly: true },
|
|
435
|
+
{ host: 'F:\\SteamLibrary', guest: 'F:\\SteamLibrary', readOnly: true },
|
|
436
|
+
],
|
|
437
|
+
};
|
|
438
|
+
t.equal(describeMissing('mw2-agent', twoFolders), 'mw2-agent wants vGPU and 2 folders (C:\\Steam\\common, F:\\SteamLibrary), but this sandbox started without them.', 'the message names each missing item');
|
|
439
|
+
t.equal(missingTip(twoFolders), 'Set sandbox.vGpu (or the mappings) in your own settings to have them in every sandbox.', 'the tip names the settings');
|
|
440
|
+
t.equal(describeMissing('api', { settings: ['sandbox.vGpu'], memoryMb: null, mappings: [] }), 'api wants vGPU, but this sandbox started without it.', 'one item reads naturally');
|
|
441
|
+
t.equal(parseWsbBoot(buildWsb(f.baseConfig, 6144, [{ host: 'C:\\a&b', guest: 'F:\\x', readOnly: true }])), { memoryMb: 6144, mappings: [{ host: 'C:\\a&b', guest: 'C:\\Mirror\\F\\x', readOnly: true }], widened: {} }, 'a sandbox started by an older version: memory and mapped folders are read back from its .wsb');
|
|
442
|
+
const widenedJoin = checkJoin({ ...base, 'sandbox.vGpu': true }, base, ['sandbox.vGpu']);
|
|
443
|
+
t.equal({ stricter: widenedJoin.stricter, shared: widenedJoin.shared }, { stricter: [], shared: ['sandbox.vGpu'] }, 'vGPU turned on at boot for another project you allowed it for: a project without it shares it instead of being refused');
|
|
444
|
+
t.check(checkJoin({ ...base, 'sandbox.vGpu': true }, base).stricter.some((s) => s.startsWith('sandbox.vGpu')), '... without that record a project without vGPU is still refused (it needs it off)');
|
|
445
|
+
// joinRunning asks before anything is registered: restart (NeedsRestart with what is missing), or continue without.
|
|
446
|
+
const storage2 = t.dir('proj-storage2');
|
|
447
|
+
const data2 = t.dir('proj-storage2', 'data', 'testdata');
|
|
448
|
+
new ProjectRegistry(storage2).start({
|
|
449
|
+
launchId: '1700000000001-abcdef',
|
|
450
|
+
protections: protectionsOf(launchedRun.config),
|
|
451
|
+
primary: { host: f.workA, guest: 'C:\\Workspace\\work-a' },
|
|
452
|
+
roots: [{ host: path.dirname(games), guest: 'C:\\Projects\\temp' }],
|
|
453
|
+
boot: [],
|
|
454
|
+
atBoot: { ...runningBoot, widened: {} },
|
|
455
|
+
});
|
|
456
|
+
const joinGames = (choice) => joinRunning({
|
|
457
|
+
storageRoot: storage2,
|
|
458
|
+
dataPath: data2,
|
|
459
|
+
packageRoot: f.install,
|
|
460
|
+
hostDir: games,
|
|
461
|
+
wsbShare: false,
|
|
462
|
+
resolve: resolveFor(gamesRun),
|
|
463
|
+
decide: async () => choice,
|
|
464
|
+
});
|
|
465
|
+
const restartFor = await joinGames('restart').then(() => null, (e) => e);
|
|
466
|
+
t.check(restartFor instanceof NeedsRestart &&
|
|
467
|
+
restartFor.missing?.settings.includes('sandbox.vGpu') === true &&
|
|
468
|
+
restartFor.missing.mappings.length === 1, 'choosing "Restart with them" hands the restart offer what is missing');
|
|
469
|
+
await t.throws(() => joinGames('cancel'), 'Cancelled', '"Cancel" stops with a short line');
|
|
470
|
+
t.check(!new ProjectRegistry(storage2).read()?.projects.some((p) => p.host === games), 'neither registers the project');
|
|
471
|
+
const continued = await joinGames('continue');
|
|
472
|
+
t.equal(continued.missing?.settings, ['sandbox.vGpu'], '"Continue anyway" joins without them and says what is missing');
|
|
473
|
+
// The restart that adds it (and any launch with it mapped at boot) boots with the union.
|
|
474
|
+
const unionGen = generateSandbox({
|
|
475
|
+
packageRoot: t.packageRoot,
|
|
476
|
+
run: launchedRun,
|
|
477
|
+
harnessArgs: [],
|
|
478
|
+
probe: f.probe,
|
|
479
|
+
extraProjects: [games],
|
|
480
|
+
autoSession: false,
|
|
481
|
+
bootWants: { projects: [{ name: 'proj-games', config: gamesRun.config }], keepOff: [] },
|
|
482
|
+
});
|
|
483
|
+
const unionWsb = fs.readFileSync(unionGen.wsbPath, 'utf8');
|
|
484
|
+
t.includes(unionWsb, '<vGPU>Enable</vGPU>', 'the restart plan: vGPU on because the added project asks for it (and you allowed it)');
|
|
485
|
+
t.includes(unionWsb, '<HostFolder>' +
|
|
486
|
+
path.join(games, 'assets') +
|
|
487
|
+
'</HostFolder><SandboxFolder>C:\\Mirror\\F\\GameAssets</SandboxFolder><ReadOnly>true</ReadOnly>', "the restart plan: the added project's mapping is mapped");
|
|
488
|
+
t.includes(unionWsb, '<HostFolder>' + games + '</HostFolder><SandboxFolder>C:\\Workspace\\proj-games</SandboxFolder>', 'the restart plan: the added project itself is mapped (where it is as the launch folder)');
|
|
489
|
+
t.equal(unionGen.widened, { 'sandbox.vGpu': 'proj-games' }, 'the registry learns which boot setting was turned on for which project');
|
|
490
|
+
t.check(unionGen.projects.notes.some((n) => n.startsWith('vGPU is on in this sandbox')), 'the launch says vGPU is on for every project and why', JSON.stringify(unionGen.projects.notes));
|
|
491
|
+
t.check(nothingMissing(missingAtBoot(protectionsOf(unionGen.bootConfig), { memoryMb: unionGen.memoryMb, mappings: unionGen.mappings }, gamesRun.config, fs.existsSync)), 'after that restart the project joins with nothing missing');
|
|
492
|
+
const keptOff = generateSandbox({
|
|
493
|
+
packageRoot: t.packageRoot,
|
|
494
|
+
run: launchedRun,
|
|
495
|
+
harnessArgs: [],
|
|
496
|
+
probe: f.probe,
|
|
497
|
+
extraProjects: [games],
|
|
498
|
+
autoSession: false,
|
|
499
|
+
bootWants: { projects: [{ name: 'proj-games', config: gamesRun.config }], keepOff: ['sandbox.vGpu'] },
|
|
500
|
+
});
|
|
501
|
+
t.includes(fs.readFileSync(keptOff.wsbPath, 'utf8'), '<vGPU>Disable</vGPU>', "a device the launch folder's own file switched off stays off");
|
|
502
|
+
t.includes(fs.readFileSync(f.generate(launchedRun).wsbPath, 'utf8'), '<vGPU>Disable</vGPU>', 'without other projects nothing changes');
|
|
239
503
|
t.section('projects: wsb (Windows Sandbox command line) adapter');
|
|
240
504
|
t.equal([parseVersion('Windows Sandbox CLI version 0.4.1.0\n'), parseVersion('nothing')], ['0.4.1.0', null], 'wsb --version');
|
|
241
505
|
const help = 'Description:\n Windows Sandbox command line\n\nUsage:\n wsb [command] [options]\n\nOptions:\n --version Show version information\n\nCommands:\n start Starts a sandbox\n list Lists sandboxes\n exec Runs a command\n share Shares a folder\n stop Stops a sandbox\n connect Connects\n ip Shows the IP\n';
|