windows-development-sandbox 1.17.3 → 1.18.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 -1
- package/config.example.json +97 -4
- package/dist/app/features/accounts/accounts.def.d.ts +116 -2
- package/dist/app/features/accounts/accounts.def.js +80 -12
- package/dist/app/features/accounts/accounts.run.d.ts +29 -0
- package/dist/app/features/accounts/accounts.run.js +36 -6
- package/dist/app/features/accounts/index.d.ts +2 -0
- package/dist/app/features/accounts/index.js +4 -1
- package/dist/app/features/accounts/services.def.d.ts +111 -0
- package/dist/app/features/accounts/services.def.js +187 -0
- package/dist/app/features/accounts/services.run.d.ts +65 -0
- package/dist/app/features/accounts/services.run.js +212 -0
- package/dist/app/features/defs.d.ts +112 -1
- package/dist/app/features/defs.js +5 -0
- package/dist/app/features/settings/categories.def.js +21 -4
- package/dist/app/registry.js +5 -1
- package/dist/bin/agent-sandbox.js +2 -2
- package/dist/bin/{chunk-QLGGAG3D.js → chunk-BKF43GJ3.js} +51 -16
- package/dist/bin/{chunk-REE3EMHD.js → chunk-YD3A67RS.js} +3812 -1702
- package/dist/bin/{chunk-XYUVIVJT.js → chunk-Z5D32FN3.js} +1 -1
- package/dist/bin/claude-host.js +2 -2
- package/dist/bin/claude-sbx.js +2 -2
- package/dist/bin/codex-sbx.js +2 -2
- package/dist/bin/gemini-sbx.js +2 -2
- package/dist/bin/sandbox.js +2 -2
- package/dist/bin/sbx-hide.js +2 -2
- package/dist/bin/sbx-show.js +2 -2
- package/dist/cli/commands/launch/launch.js +30 -1
- package/dist/cli/manifest.d.ts +93 -65
- package/dist/cli/manifest.js +23 -5
- package/dist/cli/menu/pages/accounts-page.js +31 -16
- package/dist/cli/services/accounts-service.d.ts +14 -4
- package/dist/cli/services/accounts-service.js +19 -6
- package/dist/cli/services/data-collect.js +26 -1
- package/dist/core/config/defaults.js +47 -4
- package/dist/core/detect/toolchains.d.ts +15 -1
- package/dist/core/detect/toolchains.js +45 -12
- package/dist/core/local-config/overrides.js +6 -0
- package/dist/core/schema/accounts.d.ts +27 -0
- package/dist/core/schema/accounts.js +32 -0
- package/dist/core/schema/config.d.ts +239 -0
- package/dist/core/schema/config.js +6 -0
- package/dist/core/schema/pc-installs.d.ts +7 -0
- package/dist/core/schema/pc-installs.js +17 -0
- package/dist/core/schema/toolchains.d.ts +61 -0
- package/dist/core/schema/toolchains.js +106 -0
- package/dist/core/types.d.ts +18 -0
- package/dist/guest/accounts/adapter.d.ts +25 -0
- package/dist/guest/accounts/adapter.js +21 -0
- package/dist/guest/accounts/adapters.d.ts +5 -0
- package/dist/guest/accounts/adapters.js +18 -0
- package/dist/guest/accounts/apply.d.ts +41 -0
- package/dist/guest/accounts/apply.js +47 -0
- package/dist/guest/accounts/kinds/appstore.d.ts +2 -0
- package/dist/guest/accounts/kinds/appstore.js +7 -0
- package/dist/guest/accounts/kinds/cfx.d.ts +2 -0
- package/dist/guest/accounts/kinds/cfx.js +7 -0
- package/dist/guest/accounts/kinds/epic.d.ts +2 -0
- package/dist/guest/accounts/kinds/epic.js +26 -0
- package/dist/guest/accounts/kinds/expo.d.ts +2 -0
- package/dist/guest/accounts/kinds/expo.js +7 -0
- package/dist/guest/accounts/kinds/keystore.d.ts +2 -0
- package/dist/guest/accounts/kinds/keystore.js +7 -0
- package/dist/guest/accounts/kinds/play.d.ts +2 -0
- package/dist/guest/accounts/kinds/play.js +7 -0
- package/dist/guest/accounts/kinds/steam.d.ts +4 -0
- package/dist/guest/accounts/kinds/steam.js +17 -0
- package/dist/guest/accounts/kinds/unity.d.ts +2 -0
- package/dist/guest/accounts/kinds/unity.js +7 -0
- package/dist/guest/accounts/watch.d.ts +28 -0
- package/dist/guest/accounts/watch.js +78 -0
- package/dist/guest/apps/resolvers-gamedev.d.ts +2 -0
- package/dist/guest/apps/resolvers-gamedev.js +1 -0
- package/dist/guest/apps/resolvers-mobile.d.ts +2 -0
- package/dist/guest/apps/resolvers-mobile.js +1 -0
- package/dist/guest/apps/resolvers.js +4 -0
- package/dist/guest/boot/boot.d.ts +5 -0
- package/dist/guest/boot/boot.js +35 -1
- package/dist/guest/daemon/accounts.d.ts +3 -0
- package/dist/guest/daemon/accounts.js +25 -0
- package/dist/guest/daemon/daemon.js +2 -0
- package/dist/guest/daemon/idle-shutdown.js +3 -1
- package/dist/guest/daemon/sessions.js +2 -0
- package/dist/guest/devtools/android.d.ts +2 -0
- package/dist/guest/devtools/android.js +7 -0
- package/dist/guest/devtools/devtool.d.ts +9 -0
- package/dist/guest/devtools/devtool.js +5 -0
- package/dist/guest/devtools/fivem.d.ts +2 -0
- package/dist/guest/devtools/fivem.js +7 -0
- package/dist/guest/devtools/registry.d.ts +6 -0
- package/dist/guest/devtools/registry.js +12 -0
- package/dist/guest/devtools/steam.d.ts +2 -0
- package/dist/guest/devtools/steam.js +228 -0
- package/dist/guest/devtools/unity.d.ts +2 -0
- package/dist/guest/devtools/unity.js +7 -0
- package/dist/guest/entries/daemon.js +2 -0
- package/dist/guest/entries/tool.d.ts +1 -0
- package/dist/guest/entries/tool.js +17 -0
- package/dist/guest/toolchains/engines/godot.d.ts +4 -0
- package/dist/guest/toolchains/engines/godot.js +4 -0
- package/dist/guest/toolchains/engines/unity-release.d.ts +15 -0
- package/dist/guest/toolchains/engines/unity-release.js +6 -0
- package/dist/guest/toolchains/engines/unity.d.ts +4 -0
- package/dist/guest/toolchains/engines/unity.js +4 -0
- package/dist/guest/toolchains/engines/unreal-engines.d.ts +4 -0
- package/dist/guest/toolchains/engines/unreal-engines.js +4 -0
- package/dist/guest/toolchains/fivem/artifacts.d.ts +6 -0
- package/dist/guest/toolchains/fivem/artifacts.js +7 -0
- package/dist/guest/toolchains/fivem/fivem.d.ts +4 -0
- package/dist/guest/toolchains/fivem/fivem.js +4 -0
- package/dist/guest/toolchains/installers.d.ts +12 -0
- package/dist/guest/toolchains/installers.js +39 -0
- package/dist/guest/toolchains/languages/java.js +1 -1
- package/dist/guest/toolchains/languages/kotlin.d.ts +3 -0
- package/dist/guest/toolchains/languages/kotlin.js +6 -0
- package/dist/guest/toolchains/mobile/android-repo.d.ts +11 -0
- package/dist/guest/toolchains/mobile/android-repo.js +10 -0
- package/dist/guest/toolchains/mobile/android.d.ts +17 -0
- package/dist/guest/toolchains/mobile/android.js +16 -0
- package/dist/guest/toolchains/mobile/dart.d.ts +4 -0
- package/dist/guest/toolchains/mobile/dart.js +4 -0
- package/dist/guest/toolchains/mobile/flutter.d.ts +4 -0
- package/dist/guest/toolchains/mobile/flutter.js +4 -0
- package/dist/guest/toolchains/mobile/react-native.d.ts +4 -0
- package/dist/guest/toolchains/mobile/react-native.js +4 -0
- package/dist/guest/toolchains/native/unreal.d.ts +3 -7
- package/dist/guest/toolchains/native/unreal.js +16 -167
- package/dist/guest/toolchains/native/visual-studio.d.ts +15 -0
- package/dist/guest/toolchains/native/visual-studio.js +159 -0
- package/dist/guest/toolchains/native/vs-request.d.ts +19 -0
- package/dist/guest/toolchains/native/vs-request.js +46 -0
- package/dist/guest/toolchains/not-yet.d.ts +2 -0
- package/dist/guest/toolchains/not-yet.js +6 -0
- package/dist/guest/toolchains/persisted.d.ts +48 -0
- package/dist/guest/toolchains/persisted.js +159 -0
- package/dist/guest/toolchains/plan.js +80 -4
- package/dist/guest/toolchains/steam/apps.d.ts +27 -0
- package/dist/guest/toolchains/steam/apps.js +112 -0
- package/dist/guest/toolchains/steam/client.d.ts +5 -0
- package/dist/guest/toolchains/steam/client.js +67 -0
- package/dist/guest/toolchains/steam/commands.d.ts +58 -0
- package/dist/guest/toolchains/steam/commands.js +155 -0
- package/dist/guest/toolchains/steam/steam.d.ts +4 -0
- package/dist/guest/toolchains/steam/steam.js +61 -0
- package/dist/guest/toolchains/steam/steamcmd-install.d.ts +29 -0
- package/dist/guest/toolchains/steam/steamcmd-install.js +177 -0
- package/dist/guest/toolchains/steam/steamcmd.d.ts +6 -0
- package/dist/guest/toolchains/steam/steamcmd.js +23 -0
- package/dist/guest/toolchains/step.d.ts +10 -0
- package/dist/host/accounts/deliver.d.ts +26 -0
- package/dist/host/accounts/deliver.js +80 -0
- package/dist/host/accounts/handoff.d.ts +17 -0
- package/dist/host/accounts/handoff.js +110 -0
- package/dist/host/accounts/index.d.ts +6 -0
- package/dist/host/accounts/index.js +8 -0
- package/dist/host/accounts/kinds/appstore.d.ts +2 -0
- package/dist/host/accounts/kinds/appstore.js +10 -0
- package/dist/host/accounts/kinds/cfx.d.ts +2 -0
- package/dist/host/accounts/kinds/cfx.js +7 -0
- package/dist/host/accounts/kinds/epic.d.ts +2 -0
- package/dist/host/accounts/kinds/epic.js +15 -0
- package/dist/host/accounts/kinds/expo.d.ts +2 -0
- package/dist/host/accounts/kinds/expo.js +7 -0
- package/dist/host/accounts/kinds/keystore.d.ts +2 -0
- package/dist/host/accounts/kinds/keystore.js +7 -0
- package/dist/host/accounts/kinds/play.d.ts +2 -0
- package/dist/host/accounts/kinds/play.js +7 -0
- package/dist/host/accounts/kinds/steam.d.ts +6 -0
- package/dist/host/accounts/kinds/steam.js +31 -0
- package/dist/host/accounts/kinds/unity.d.ts +2 -0
- package/dist/host/accounts/kinds/unity.js +13 -0
- package/dist/host/accounts/leases.d.ts +40 -0
- package/dist/host/accounts/leases.js +62 -0
- package/dist/host/accounts/source.d.ts +21 -0
- package/dist/host/accounts/source.js +15 -0
- package/dist/host/accounts/sources.d.ts +5 -0
- package/dist/host/accounts/sources.js +18 -0
- package/dist/host/accounts/store.d.ts +23 -0
- package/dist/host/accounts/store.js +74 -0
- package/dist/host/audit/log.d.ts +1 -1
- package/dist/host/launch/generate.d.ts +2 -0
- package/dist/host/launch/generate.js +16 -1
- package/dist/host/launch/hints/android.d.ts +3 -0
- package/dist/host/launch/hints/android.js +3 -0
- package/dist/host/launch/hints/engines.d.ts +3 -0
- package/dist/host/launch/hints/engines.js +3 -0
- package/dist/host/launch/hints/fivem.d.ts +3 -0
- package/dist/host/launch/hints/fivem.js +3 -0
- package/dist/host/launch/hints/hint.d.ts +2 -0
- package/dist/host/launch/hints/hint.js +1 -0
- package/dist/host/launch/hints/index.d.ts +5 -0
- package/dist/host/launch/hints/index.js +29 -0
- package/dist/host/launch/hints/mobile.d.ts +3 -0
- package/dist/host/launch/hints/mobile.js +3 -0
- package/dist/host/launch/hints/steam.d.ts +7 -0
- package/dist/host/launch/hints/steam.js +59 -0
- package/dist/host/launch/index.d.ts +2 -2
- package/dist/host/launch/index.js +2 -2
- package/dist/host/launch/mappings.js +2 -0
- package/dist/host/launch/session-file.js +2 -0
- package/dist/host/launch/stage.js +10 -1
- package/dist/host/launch/toolchains.d.ts +7 -0
- package/dist/host/launch/toolchains.js +11 -0
- package/dist/host/pc-installs/discover.d.ts +19 -0
- package/dist/host/pc-installs/discover.js +59 -0
- package/dist/host/pc-installs/epic.d.ts +2 -0
- package/dist/host/pc-installs/epic.js +7 -0
- package/dist/host/pc-installs/index.d.ts +3 -0
- package/dist/host/pc-installs/index.js +2 -0
- package/dist/host/pc-installs/source.d.ts +9 -0
- package/dist/host/pc-installs/source.js +1 -0
- package/dist/host/pc-installs/steam.d.ts +16 -0
- package/dist/host/pc-installs/steam.js +143 -0
- package/dist/host/pc-installs/unity.d.ts +2 -0
- package/dist/host/pc-installs/unity.js +7 -0
- package/dist/host/pc-installs/unreal.d.ts +2 -0
- package/dist/host/pc-installs/unreal.js +7 -0
- package/dist/host/profile/accounts.d.ts +21 -6
- package/dist/host/profile/accounts.js +108 -28
- package/dist/host/profile/claude-login.d.ts +32 -2
- package/dist/host/profile/claude-login.js +100 -8
- package/dist/host/profile/index.d.ts +1 -1
- package/dist/host/profile/index.js +1 -1
- package/dist/host/secrets/launch-secrets.js +1 -0
- package/dist/runtime/agent.js +321 -9
- package/dist/runtime/daemon.js +1987 -604
- package/dist/runtime/db.js +334 -11
- package/dist/runtime/main.js +2519 -723
- package/dist/runtime/netproxy.js +321 -9
- package/dist/runtime/tool.js +28549 -0
- package/dist/runtime/view.js +321 -9
- package/dist/selftest/accounts.test.js +172 -1
- package/dist/selftest/agent-paths.test.js +1 -0
- package/dist/selftest/android.test.d.ts +2 -0
- package/dist/selftest/android.test.js +7 -0
- package/dist/selftest/app.test.js +1 -1
- package/dist/selftest/engines.test.d.ts +2 -0
- package/dist/selftest/engines.test.js +7 -0
- package/dist/selftest/fivem.test.d.ts +2 -0
- package/dist/selftest/fivem.test.js +7 -0
- package/dist/selftest/generate.test.js +1 -1
- package/dist/selftest/index.js +18 -0
- package/dist/selftest/menu-screens.js +1 -0
- package/dist/selftest/menu.test.js +2 -1
- package/dist/selftest/mobile.test.d.ts +2 -0
- package/dist/selftest/mobile.test.js +7 -0
- package/dist/selftest/pc-installs.test.d.ts +2 -0
- package/dist/selftest/pc-installs.test.js +111 -0
- package/dist/selftest/persisted-installs.test.d.ts +2 -0
- package/dist/selftest/persisted-installs.test.js +107 -0
- package/dist/selftest/projects.test.js +6 -4
- package/dist/selftest/service-accounts.test.d.ts +2 -0
- package/dist/selftest/service-accounts.test.js +320 -0
- package/dist/selftest/steam.test.d.ts +2 -0
- package/dist/selftest/steam.test.js +316 -0
- package/dist/selftest/storage-helper.test.js +31 -8
- package/dist/selftest/support/engine-golden.js +3 -0
- package/dist/selftest/support/fixtures.d.ts +87 -0
- package/dist/selftest/support/fixtures.js +4 -3
- package/dist/selftest/support/pc-memory.d.ts +2 -0
- package/dist/selftest/support/pc-memory.js +17 -0
- package/dist/selftest/support/web-preview.js +20 -1
- package/dist/selftest/unity.test.d.ts +2 -0
- package/dist/selftest/unity.test.js +7 -0
- package/dist/shared/accounts/fingerprint.d.ts +1 -0
- package/dist/shared/accounts/fingerprint.js +20 -0
- package/dist/shared/accounts/index.d.ts +5 -0
- package/dist/shared/accounts/index.js +7 -0
- package/dist/shared/accounts/kinds/epic.d.ts +10 -0
- package/dist/shared/accounts/kinds/epic.js +56 -0
- package/dist/shared/accounts/kinds/steam.d.ts +28 -0
- package/dist/shared/accounts/kinds/steam.js +99 -0
- package/dist/shared/accounts/kinds.d.ts +41 -0
- package/dist/shared/accounts/kinds.js +154 -0
- package/dist/shared/accounts/payloads.d.ts +151 -0
- package/dist/shared/accounts/payloads.js +128 -0
- package/dist/shared/apps/catalogue-gamedev.d.ts +2 -0
- package/dist/shared/apps/catalogue-gamedev.js +1 -0
- package/dist/shared/apps/catalogue-mobile.d.ts +2 -0
- package/dist/shared/apps/catalogue-mobile.js +1 -0
- package/dist/shared/apps/catalogue-modding.d.ts +2 -0
- package/dist/shared/apps/catalogue-modding.js +1 -0
- package/dist/shared/apps/catalogue.d.ts +1 -0
- package/dist/shared/apps/catalogue.js +6 -1
- package/dist/shared/channel/schema.d.ts +183 -0
- package/dist/shared/channel/secrets.d.ts +42 -0
- package/dist/shared/channel/secrets.js +3 -0
- package/dist/shared/download/downloader.d.ts +7 -0
- package/dist/shared/download/downloader.js +10 -3
- package/dist/shared/installs.d.ts +19 -0
- package/dist/shared/installs.js +13 -0
- package/dist/shared/io/bounded.d.ts +6 -0
- package/dist/shared/io/bounded.js +38 -0
- package/dist/shared/io/index.d.ts +2 -0
- package/dist/shared/io/index.js +2 -0
- package/dist/shared/io/text.d.ts +9 -0
- package/dist/shared/io/text.js +18 -0
- package/dist/shared/paths/guest-paths.js +1 -1
- package/dist/shared/paths/index.d.ts +1 -0
- package/dist/shared/paths/index.js +1 -0
- package/dist/shared/paths/pc-installs.d.ts +20 -0
- package/dist/shared/paths/pc-installs.js +19 -0
- package/dist/shared/vdf.d.ts +25 -0
- package/dist/shared/vdf.js +151 -0
- package/dist/sync/sync-cycle.js +9 -0
- package/dist/web/index.html +1 -1
- package/dist/web/{main-JTH3FT4O.js → main-CWIF4VQI.js} +63 -61
- package/native/csharp/HcsHost/AssemblyInfo.cs +3 -3
- package/native/csharp/HostTools/AssemblyInfo.cs +3 -3
- package/native/csharp/StorageHelper/AssemblyInfo.cs +3 -3
- package/package.json +1 -1
- package/sandbox/scripts/add-firewall-port.ps1 +13 -0
- package/sandbox/templates/fivem/README.txt +2 -0
- package/schemas/config.schema.json +485 -0
- package/schemas/sandbox-config.schema.json +416 -0
|
@@ -551,7 +551,7 @@ export const appSuite = {
|
|
|
551
551
|
const codexMenu = menuView(agentPage(codex), { category: 'codex', refresh: false });
|
|
552
552
|
t.check(codexMenu.enterLabel('codex', 'codex:main') === 'use' &&
|
|
553
553
|
['s', 'p', 'd', 'r', 'x'].every((k) => codexMenu.actions.some((a) => a.key === k)) &&
|
|
554
|
-
accountsPage({ agent: 'codex', agents: [codex] }).sections[0].cards === true, 'accounts: the page offers use on Enter and d/r/x on a login; the codex agent is a card');
|
|
554
|
+
accountsPage({ agent: 'codex', agents: [codex], services: [] }).sections[0].cards === true, 'accounts: the page offers use on Enter and d/r/x on a login; the codex agent is a card');
|
|
555
555
|
const useDef = definitionFor('account', ['use']);
|
|
556
556
|
t.check(JSON.stringify(cliInput(useDef, parseCli(['account', 'use', 'work', '--no-restart']))) ===
|
|
557
557
|
JSON.stringify({ name: 'work', noRestart: true }) &&
|
|
@@ -38,7 +38,7 @@ export const generateSuite = {
|
|
|
38
38
|
'sandbox/csharp/LinkGate.cs',
|
|
39
39
|
];
|
|
40
40
|
const missing = expectedFiles.filter((file) => !fs.existsSync(path.join(gen.launchPath, file)));
|
|
41
|
-
t.check(missing.length === 0 && fs.readdirSync(path.join(gen.launchPath, 'runtime')).length ===
|
|
41
|
+
t.check(missing.length === 0 && fs.readdirSync(path.join(gen.launchPath, 'runtime')).length === 8, 'the launch folder has the runtime (8 self-contained files), the C# sources and the boot scripts', missing.join(', '));
|
|
42
42
|
const logon = fs.readFileSync(path.join(gen.launchPath, 'sandbox', 'boot', 'logon.cmd'), 'utf8');
|
|
43
43
|
t.check(logon.indexOf('trust.cmd') < logon.indexOf('wt.exe') &&
|
|
44
44
|
logon.includes('tools\\terminal\\wt.exe') &&
|
package/dist/selftest/index.js
CHANGED
|
@@ -11,6 +11,15 @@ import { createFixtures } from './support/fixtures.js';
|
|
|
11
11
|
import { createHarness } from './support/harness.js';
|
|
12
12
|
import { liveTestsAvailable } from './support/live.js';
|
|
13
13
|
import { accountsSuite } from './accounts.test.js';
|
|
14
|
+
import { serviceAccountsSuite } from './service-accounts.test.js';
|
|
15
|
+
import { persistedInstallsSuite } from './persisted-installs.test.js';
|
|
16
|
+
import { pcInstallsSuite } from './pc-installs.test.js';
|
|
17
|
+
import { steamSuite } from './steam.test.js';
|
|
18
|
+
import { enginesSuite } from './engines.test.js';
|
|
19
|
+
import { unitySuite } from './unity.test.js';
|
|
20
|
+
import { fivemSuite } from './fivem.test.js';
|
|
21
|
+
import { androidSuite } from './android.test.js';
|
|
22
|
+
import { mobileSuite } from './mobile.test.js';
|
|
14
23
|
import { credentialsSuite } from './credentials.test.js';
|
|
15
24
|
import { vpnSuite } from './vpn.test.js';
|
|
16
25
|
import { githubSuite } from './github.test.js';
|
|
@@ -101,6 +110,8 @@ export const SUITES = [
|
|
|
101
110
|
credentialsSuite,
|
|
102
111
|
vpnSuite,
|
|
103
112
|
githubSuite,
|
|
113
|
+
serviceAccountsSuite,
|
|
114
|
+
pcInstallsSuite,
|
|
104
115
|
workspaceViewSuite,
|
|
105
116
|
auditSuite,
|
|
106
117
|
// an untrusted sandbox: what the host refuses to do with what it finds
|
|
@@ -117,6 +128,13 @@ export const SUITES = [
|
|
|
117
128
|
// pure helpers and the command line
|
|
118
129
|
layoutSuite,
|
|
119
130
|
toolchainsSuite,
|
|
131
|
+
persistedInstallsSuite,
|
|
132
|
+
steamSuite,
|
|
133
|
+
enginesSuite,
|
|
134
|
+
unitySuite,
|
|
135
|
+
fivemSuite,
|
|
136
|
+
androidSuite,
|
|
137
|
+
mobileSuite,
|
|
120
138
|
detectSuite,
|
|
121
139
|
networkSuite,
|
|
122
140
|
personalizationSuite,
|
|
@@ -618,9 +618,10 @@ export const menuSuite = {
|
|
|
618
618
|
!stoppedItems.some((i) => i.value === 'act:stop'), 'with no sandbox running, Sandbox offers to start one (Status and Databases) instead of dead rows');
|
|
619
619
|
const noLogins = accountsOptions({
|
|
620
620
|
agent: 'claude',
|
|
621
|
+
services: [],
|
|
621
622
|
agents: [{ name: 'claude', kept: true, canSavePc: true, accounts: [] }],
|
|
622
623
|
});
|
|
623
|
-
t.equal(noLogins.items.map((i) => i.value), ['@save-sandbox', '@save-pc'], 'with no saved login, Accounts offers to save the sandbox login
|
|
624
|
+
t.equal(noLogins.items.map((i) => i.value), ['@save-sandbox', '@save-pc', '@save-key'], 'with no saved login, Accounts offers to save the sandbox login, this PC login or an API key (Enter)');
|
|
624
625
|
t.section('apps in a few groups');
|
|
625
626
|
const groupIds = appsCategories(user2).map((c) => c.id);
|
|
626
627
|
const appItems = appsItems(user2, t.dir('apps-groups'), new Draft()).filter((i) => i.value !== REQUEST_APP);
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
// pcInstalls (this PC's games, engines and editors, read-only in the sandbox): where each one appears, what is
|
|
2
|
+
// refused, that a project file can never ask for them, and the launch writing them into the .wsb and session.json
|
|
3
|
+
// (paths in the sandbox only). Also the new toolchains' detection: markers, what one brings along, licence gates, and
|
|
4
|
+
// that a project can never accept a licence for you. Temp folders and fake sources only.
|
|
5
|
+
import fs from 'node:fs';
|
|
6
|
+
import path from 'node:path';
|
|
7
|
+
import { DEFAULTS } from '../core/config/index.js';
|
|
8
|
+
import { decideToolchains, LICENSED_TOOLCHAINS } from '../core/detect/index.js';
|
|
9
|
+
import { applyOverrides, normalizeOverrides, OFF_IS_SAFER } from '../core/local-config/index.js';
|
|
10
|
+
import { LocalOverridesSchema } from '../core/schema/index.js';
|
|
11
|
+
import { discoverPcInstalls } from '../host/pc-installs/index.js';
|
|
12
|
+
import { generateSandbox } from '../host/launch/index.js';
|
|
13
|
+
import { isValidGuestPath, PC_INSTALLS_GUEST } from '../shared/paths/index.js';
|
|
14
|
+
const PC = { localAppData: '', appData: '', programData: '' };
|
|
15
|
+
export const pcInstallsSuite = {
|
|
16
|
+
name: 'pc-installs',
|
|
17
|
+
title: "this PC's installs mapped read-only; new toolchains' markers, implications and licence gates",
|
|
18
|
+
run: async (t, f) => {
|
|
19
|
+
t.section('placing them');
|
|
20
|
+
const game = t.dir('pc-games', 'Spacewar');
|
|
21
|
+
const engine = t.dir('pc-engines', 'UE_5.4');
|
|
22
|
+
const installs = (items) => ({
|
|
23
|
+
kind: 'steam-game',
|
|
24
|
+
setting: 'steamGames',
|
|
25
|
+
find: () => items,
|
|
26
|
+
});
|
|
27
|
+
const steam = installs([
|
|
28
|
+
{ kind: 'steam-game', id: '480', name: 'Spacewar', host: game, guest: '' },
|
|
29
|
+
{ kind: 'steam-game', id: '481', name: 'Gone', host: path.join(game, 'missing'), guest: '' },
|
|
30
|
+
{ kind: 'steam-game', id: '..', name: 'Climber', host: game, guest: '' },
|
|
31
|
+
]);
|
|
32
|
+
const unreal = {
|
|
33
|
+
kind: 'unreal',
|
|
34
|
+
setting: 'unrealEngines',
|
|
35
|
+
find: () => [
|
|
36
|
+
{ kind: 'unreal', id: 'UE_5.4', name: 'Unreal Engine 5.4', version: '5.4', host: engine, guest: '' },
|
|
37
|
+
],
|
|
38
|
+
};
|
|
39
|
+
const settings = { ...DEFAULTS.pcInstalls, steamGames: [480, 481], unrealEngines: true };
|
|
40
|
+
const found = discoverPcInstalls(settings, { packageRoot: t.packageRoot, storageRoot: f.baseConfig.storage.root, sources: [steam, unreal] }, PC);
|
|
41
|
+
t.equal(found.mappings.map((m) => [m.guest, m.readOnly]), [
|
|
42
|
+
[PC_INSTALLS_GUEST + '\\steam\\480', true],
|
|
43
|
+
[PC_INSTALLS_GUEST + '\\unreal\\UE_5.4', true],
|
|
44
|
+
], 'each one appears read-only under C:\\PcInstalls by its kind and id');
|
|
45
|
+
t.check(found.notes.some((n) => n.includes('Gone')) && found.notes.some((n) => n.includes('Climber')), 'a folder that is not there, or an id that is not a folder name, is left out with a note');
|
|
46
|
+
t.check(!JSON.stringify(found.manifest).includes(game) &&
|
|
47
|
+
found.manifest.items.every((i) => i.guest.startsWith(PC_INSTALLS_GUEST)), 'the manifest for the sandbox holds no path of this PC');
|
|
48
|
+
t.equal(discoverPcInstalls(DEFAULTS.pcInstalls, { packageRoot: t.packageRoot, storageRoot: f.baseConfig.storage.root, sources: [steam] }, PC).mappings, [], 'off by default: nothing is looked for');
|
|
49
|
+
const unsafe = installs([
|
|
50
|
+
{ kind: 'steam-game', id: '1', name: 'Storage', host: f.baseConfig.storage.root, guest: '' },
|
|
51
|
+
]);
|
|
52
|
+
t.check(discoverPcInstalls({ ...settings, unrealEngines: false }, { packageRoot: t.packageRoot, storageRoot: f.baseConfig.storage.root, sources: [unsafe] }, PC).mappings.length === 0, "this tool's own folders are refused like any other mapping");
|
|
53
|
+
t.check(!isValidGuestPath('C:\\PcInstalls\\mine'), 'no other mapping may use C:\\PcInstalls');
|
|
54
|
+
t.section('yours only');
|
|
55
|
+
t.check(!('pcInstalls' in LocalOverridesSchema.shape), 'a project file has no pcInstalls');
|
|
56
|
+
await t.throws(() => normalizeOverrides({ pcInstalls: { steamGames: true } }, f.workA, 'project'), 'not valid', 'a project file asking for them is refused');
|
|
57
|
+
t.section('the launch');
|
|
58
|
+
const run = await f.run({}, f.makeConfig());
|
|
59
|
+
const launched = generateSandbox({
|
|
60
|
+
packageRoot: t.packageRoot,
|
|
61
|
+
run,
|
|
62
|
+
harnessArgs: [],
|
|
63
|
+
probe: f.probe,
|
|
64
|
+
pcLanguages: [],
|
|
65
|
+
pcInstalls: { mappings: found.mappings, manifest: found.manifest },
|
|
66
|
+
});
|
|
67
|
+
const wsb = fs.readFileSync(launched.wsbPath, 'utf8');
|
|
68
|
+
const session = f.readJson(launched.sessionPath);
|
|
69
|
+
t.check(wsb.includes(game) && wsb.includes(PC_INSTALLS_GUEST + '\\steam\\480'), 'the .wsb maps them');
|
|
70
|
+
t.check(session.pcInstalls?.items.map((i) => i.id).join() === '480,UE_5.4' &&
|
|
71
|
+
!JSON.stringify(session.pcInstalls).includes(game), 'session.json lists them by their place in the sandbox only');
|
|
72
|
+
t.section('detection of the new toolchains');
|
|
73
|
+
const tc = structuredClone(DEFAULTS.toolchains);
|
|
74
|
+
const decide = (entries, hints = {}, settingsOf = tc) => decideToolchains(settingsOf, entries, [], hints);
|
|
75
|
+
const godot = decide(['project.godot']);
|
|
76
|
+
const steamApp = decide(['steam_appid.txt']);
|
|
77
|
+
const unity = decide(['ProjectSettings/ProjectVersion.txt']);
|
|
78
|
+
t.check(godot.godot.on && steamApp.steam.on && decide(['src/Main.kt']).java.on, 'project.godot, steam_appid.txt and *.kt turn their toolchains on');
|
|
79
|
+
t.check(!unity.unity.on && unity.unity.reason.includes('toolchains.unity.acceptLicense'), 'Unity is licensed: "auto" waits for acceptLicense and says so');
|
|
80
|
+
const flutter = decide([], { flutter: 'pubspec.yaml uses Flutter' });
|
|
81
|
+
t.check(flutter.flutter.on &&
|
|
82
|
+
!flutter.android.on &&
|
|
83
|
+
flutter.android.reason.includes('Flutter') &&
|
|
84
|
+
flutter.android.reason.includes('acceptLicense') &&
|
|
85
|
+
!flutter.java.on, 'Flutter would bring the Android SDK, but not before its licence is accepted (and no JDK then)');
|
|
86
|
+
const accepted = structuredClone(tc);
|
|
87
|
+
accepted.android.acceptLicense = true;
|
|
88
|
+
const flutterOk = decide([], { reactNative: 'package.json uses react-native' }, accepted);
|
|
89
|
+
t.check(flutterOk.android.on && flutterOk.java.on && flutterOk.java.reason.includes('JDK'), 'React Native brings the Android SDK, and the Android SDK a JDK');
|
|
90
|
+
const godotNet = structuredClone(tc);
|
|
91
|
+
godotNet.godot.dotnet = true;
|
|
92
|
+
t.check(decide(['project.godot'], {}, godotNet).dotnet.on, "Godot's .NET build brings .NET");
|
|
93
|
+
const fivem = decide(['fxmanifest.lua']);
|
|
94
|
+
t.check(!fivem.fivem.on && fivem.fivem.reason.includes('fivem.acceptLicense'), 'the FiveM server is licensed too');
|
|
95
|
+
t.section('a project never accepts a licence or shares a sign-in');
|
|
96
|
+
t.check(LICENSED_TOOLCHAINS.every((n) => OFF_IS_SAFER.includes('toolchains.' + n + '.acceptLicense')) &&
|
|
97
|
+
OFF_IS_SAFER.includes('accounts.epic.share') &&
|
|
98
|
+
OFF_IS_SAFER.includes('accounts.appstore.share'), 'every acceptLicense and every share is a protection a project can only turn off');
|
|
99
|
+
const mine = structuredClone(DEFAULTS);
|
|
100
|
+
const merged = applyOverrides(mine, normalizeOverrides({
|
|
101
|
+
toolchains: {
|
|
102
|
+
unity: { acceptLicense: true },
|
|
103
|
+
msvc: { acceptLicense: true },
|
|
104
|
+
android: { acceptLicense: true },
|
|
105
|
+
},
|
|
106
|
+
}, f.workA, 'project'));
|
|
107
|
+
t.check(!merged.toolchains.unity.acceptLicense &&
|
|
108
|
+
!merged.toolchains.msvc.acceptLicense &&
|
|
109
|
+
!merged.toolchains.android.acceptLicense, 'a project asking to accept a licence leaves it unaccepted');
|
|
110
|
+
},
|
|
111
|
+
};
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
// Large installs kept between sandboxes (guest/toolchains/persisted.ts): the staging folder and its TEMP, the marker,
|
|
2
|
+
// the refusal when the disk is short (an injected statfs), keeping only keepVersions, the records `sandbox data`
|
|
3
|
+
// reads, and which Visual Studio the toolchains ask for (vs-request.ts). Temp folders only.
|
|
4
|
+
import fs from 'node:fs';
|
|
5
|
+
import path from 'node:path';
|
|
6
|
+
import { DEFAULTS } from '../core/config/index.js';
|
|
7
|
+
import { assertLocalRoom, ensurePersisted, installRecords, InstallRecordsSchema, LOCAL_RESERVE_BYTES, recordUse, } from '../guest/toolchains/persisted.js';
|
|
8
|
+
import { BUILD_TOOLS_COMPONENTS, UNREAL_COMPONENTS, visualStudioWanted, } from '../guest/toolchains/native/vs-request.js';
|
|
9
|
+
import { collectDataEntries } from '../cli/services/data-collect.js';
|
|
10
|
+
const GB = 1024 ** 3;
|
|
11
|
+
export const persistedInstallsSuite = {
|
|
12
|
+
name: 'persisted-installs',
|
|
13
|
+
title: 'large persisted installs: staging, marker, room checks, pruning, records; the Visual Studio request',
|
|
14
|
+
run: async (t) => {
|
|
15
|
+
t.section('installing a version');
|
|
16
|
+
const tools = t.dir('persisted-tools');
|
|
17
|
+
const roomy = { toolsDir: tools, statfs: () => ({ bavail: 100 * GB, bsize: 1 }) };
|
|
18
|
+
const spec = {
|
|
19
|
+
name: 'engine',
|
|
20
|
+
version: '1.0',
|
|
21
|
+
needBytes: 2 * GB,
|
|
22
|
+
marker: 'bin/engine.exe',
|
|
23
|
+
what: 'Engine 1.0',
|
|
24
|
+
keepVersions: 2,
|
|
25
|
+
};
|
|
26
|
+
let seen = null;
|
|
27
|
+
const first = await ensurePersisted(spec, async (staging, temp) => {
|
|
28
|
+
seen = { staging, temp };
|
|
29
|
+
fs.writeFileSync(path.join(temp, 'download.part'), 'x'.repeat(10));
|
|
30
|
+
fs.mkdirSync(path.join(staging, 'bin'), { recursive: true });
|
|
31
|
+
fs.writeFileSync(path.join(staging, 'bin', 'engine.exe'), 'engine');
|
|
32
|
+
}, roomy);
|
|
33
|
+
const done = path.join(tools, 'engine', '1.0');
|
|
34
|
+
t.check(first.fresh &&
|
|
35
|
+
first.dir === done &&
|
|
36
|
+
fs.existsSync(path.join(done, '.complete.json')) &&
|
|
37
|
+
!fs.existsSync(path.join(done, '.temp')) &&
|
|
38
|
+
seen !== null &&
|
|
39
|
+
path.dirname(seen.staging) === path.join(tools, 'engine') &&
|
|
40
|
+
seen.temp.startsWith(seen.staging), 'it is built in a staging folder next to the target (TEMP inside it) and moved into place with its marker');
|
|
41
|
+
t.equal(first.sizeBytes, 'engine'.length, 'its size is counted once (the temporary files are gone)');
|
|
42
|
+
let ran = false;
|
|
43
|
+
const again = await ensurePersisted(spec, async () => {
|
|
44
|
+
ran = true;
|
|
45
|
+
}, roomy);
|
|
46
|
+
t.check(!again.fresh && !ran && again.sizeBytes === first.sizeBytes, 'a finished version is not installed again');
|
|
47
|
+
t.check(InstallRecordsSchema.safeParse(JSON.parse(fs.readFileSync(path.join(tools, 'installs.json'), 'utf8'))).success &&
|
|
48
|
+
installRecords(roomy).some((r) => r.name === 'engine' && r.version === '1.0' && r.sizeBytes === 6), 'tools\\installs.json records it with its size (what sandbox data shows)');
|
|
49
|
+
t.section('when something goes wrong');
|
|
50
|
+
await t.throws(() => ensurePersisted({ ...spec, version: '2.0' }, async () => undefined, roomy), 'without bin/engine.exe', 'an install that does not leave its marker fails');
|
|
51
|
+
t.check(!fs.existsSync(path.join(tools, 'engine', '2.0')) &&
|
|
52
|
+
!fs.readdirSync(path.join(tools, 'engine')).some((n) => n.startsWith('.staging')), 'and leaves nothing behind');
|
|
53
|
+
const short = { toolsDir: tools, statfs: () => ({ bavail: GB, bsize: 1 }) };
|
|
54
|
+
let installed = false;
|
|
55
|
+
await t.throws(() => ensurePersisted({ ...spec, version: '3.0' }, async () => {
|
|
56
|
+
installed = true;
|
|
57
|
+
}, short), 'it needs 2.0 GB', 'a disk with too little room refuses before anything is downloaded');
|
|
58
|
+
t.check(!installed, 'and the installer never ran');
|
|
59
|
+
await t.throws(() => ensurePersisted({ ...spec, version: '..' }, async () => undefined, roomy), 'not a usable', 'a version cannot climb out of tools\\');
|
|
60
|
+
await t.throws(() => Promise.resolve(assertLocalRoom(GB, 'Visual Studio', {
|
|
61
|
+
localDir: tools,
|
|
62
|
+
statfs: () => ({ bavail: LOCAL_RESERVE_BYTES, bsize: 1 }),
|
|
63
|
+
})), 'Visual Studio', "a real installer leaves 13 GB free on the sandbox's own disk");
|
|
64
|
+
t.section('keeping versions');
|
|
65
|
+
const make = (version) => ensurePersisted({ ...spec, version }, async (staging) => {
|
|
66
|
+
fs.mkdirSync(path.join(staging, 'bin'), { recursive: true });
|
|
67
|
+
fs.writeFileSync(path.join(staging, 'bin', 'engine.exe'), version);
|
|
68
|
+
}, roomy);
|
|
69
|
+
await make('1.1');
|
|
70
|
+
recordUse('engine', '1.0', roomy);
|
|
71
|
+
await make('1.2');
|
|
72
|
+
const left = fs.readdirSync(path.join(tools, 'engine')).sort();
|
|
73
|
+
t.equal(left, ['1.0', '1.2'], 'beyond keepVersions the least recently used version goes');
|
|
74
|
+
t.check(!installRecords(roomy).some((r) => r.version === '1.1'), 'and its record with it');
|
|
75
|
+
t.section('what sandbox data shows');
|
|
76
|
+
const data = t.dir('persisted-data');
|
|
77
|
+
const big = t.dir('persisted-data', 'tools', 'editor', '6000.0');
|
|
78
|
+
fs.writeFileSync(path.join(big, 'Unity.exe'), 'small here');
|
|
79
|
+
t.writeJson(path.join(data, 'tools', 'installs.json'), {
|
|
80
|
+
installs: [{ name: 'editor', version: '6000.0', sizeBytes: 7 * GB, installedAt: 'x', usedAt: 'x' }],
|
|
81
|
+
});
|
|
82
|
+
t.dir('persisted-data', 'tools', 'walked', '1.0');
|
|
83
|
+
const rows = collectDataEntries(data, t.dir('persisted-storage'));
|
|
84
|
+
t.check(rows.find((r) => r.name === 'editor')?.bytes === 7 * GB && rows.some((r) => r.name === 'walked'), 'a tool whose versions are all recorded shows the recorded size (not walked); the others are measured');
|
|
85
|
+
t.section('which Visual Studio');
|
|
86
|
+
const tc = structuredClone(DEFAULTS.toolchains);
|
|
87
|
+
t.equal(visualStudioWanted(tc), null, 'no toolchain that needs it: none');
|
|
88
|
+
tc.flutter.enabled = true;
|
|
89
|
+
tc.flutter.windowsDesktop = true;
|
|
90
|
+
const tools1 = visualStudioWanted(tc);
|
|
91
|
+
t.check(tools1?.product === 'buildtools' &&
|
|
92
|
+
BUILD_TOOLS_COMPONENTS.every((c) => tools1.components.includes(c)) &&
|
|
93
|
+
tools1.licence === 'toolchains.msvc.acceptLicense' &&
|
|
94
|
+
!tools1.accepted, "Flutter desktop: the Build Tools' C++ parts, under the MSVC licence setting");
|
|
95
|
+
tc.unity.enabled = true;
|
|
96
|
+
tc.unity.modules = ['windows-il2cpp'];
|
|
97
|
+
tc.unreal.enabled = true;
|
|
98
|
+
tc.unreal.acceptLicense = true;
|
|
99
|
+
tc.unreal.components = ['Microsoft.VisualStudio.Component.VC.Llvm.Clang'];
|
|
100
|
+
const all = visualStudioWanted(tc);
|
|
101
|
+
t.check(all?.product === 'community' &&
|
|
102
|
+
all.accepted &&
|
|
103
|
+
all.for.join() === 'unreal,flutter,unity' &&
|
|
104
|
+
UNREAL_COMPONENTS.every((c) => all.components.includes(c)) &&
|
|
105
|
+
all.components.includes('Microsoft.VisualStudio.Component.VC.Llvm.Clang'), 'with Unreal: one Community install serves all of them');
|
|
106
|
+
},
|
|
107
|
+
};
|
|
@@ -22,6 +22,7 @@ import { parseCli, parseSessionWant } from '../cli/args.js';
|
|
|
22
22
|
import { severalAgentsArgv } from '../cli/menu/index.js';
|
|
23
23
|
import { generateSandbox } from '../host/launch/index.js';
|
|
24
24
|
import { describeSessions } from '../cli/commands/projects/index.js';
|
|
25
|
+
import { onFixedPc } from './support/pc-memory.js';
|
|
25
26
|
/** The error `fn` throws, or null. */
|
|
26
27
|
const caught = async (fn) => {
|
|
27
28
|
try {
|
|
@@ -518,7 +519,8 @@ export const projectsSuite = {
|
|
|
518
519
|
notRegistered &&
|
|
519
520
|
(await joinGames('continue')).missing?.settings.join() === 'sandbox.vGpu', '"Restart with them" hands the restart offer what is missing, "Cancel" stops with a short line (neither registers the project), "Continue anyway" joins and says what is missing', cancelled);
|
|
520
521
|
// The restart that adds it (and any launch with it mapped at boot) boots with the union.
|
|
521
|
-
|
|
522
|
+
// On a pretend PC with plenty of RAM: the memory asked for is not lowered to what this machine can keep resident.
|
|
523
|
+
const unionGen = onFixedPc(() => generateSandbox({
|
|
522
524
|
packageRoot: t.packageRoot,
|
|
523
525
|
run: launchedRun,
|
|
524
526
|
harnessArgs: [],
|
|
@@ -526,7 +528,7 @@ export const projectsSuite = {
|
|
|
526
528
|
extraProjects: [games],
|
|
527
529
|
autoSession: false,
|
|
528
530
|
bootWants: { projects: [{ name: 'proj-games', config: gamesRun.config }], keepOff: [] },
|
|
529
|
-
});
|
|
531
|
+
}));
|
|
530
532
|
const unionWsb = fs.readFileSync(unionGen.wsbPath, 'utf8');
|
|
531
533
|
t.check(unionWsb.includes('<vGPU>Enable</vGPU>') &&
|
|
532
534
|
unionWsb.includes('<HostFolder>' +
|
|
@@ -536,7 +538,7 @@ export const projectsSuite = {
|
|
|
536
538
|
const unionLearns = unionGen.widened['sandbox.vGpu'] === 'proj-games' &&
|
|
537
539
|
unionGen.projects.notes.some((n) => n.startsWith('vGPU is on in this sandbox')) &&
|
|
538
540
|
nothingMissing(missingAtBoot(protectionsOf(unionGen.bootConfig), { memoryMb: unionGen.memoryMb, mappings: unionGen.mappings }, gamesRun.config, fs.existsSync));
|
|
539
|
-
const keptOff = generateSandbox({
|
|
541
|
+
const keptOff = onFixedPc(() => generateSandbox({
|
|
540
542
|
packageRoot: t.packageRoot,
|
|
541
543
|
run: launchedRun,
|
|
542
544
|
harnessArgs: [],
|
|
@@ -544,7 +546,7 @@ export const projectsSuite = {
|
|
|
544
546
|
extraProjects: [games],
|
|
545
547
|
autoSession: false,
|
|
546
548
|
bootWants: { projects: [{ name: 'proj-games', config: gamesRun.config }], keepOff: ['sandbox.vGpu'] },
|
|
547
|
-
});
|
|
549
|
+
}));
|
|
548
550
|
t.check(unionLearns && fs.readFileSync(keptOff.wsbPath, 'utf8').includes('<vGPU>Disable</vGPU>'), "the registry learns which setting was turned on for which project, after that restart nothing is missing; a device the launch folder's own file switched off stays off", JSON.stringify(unionGen.projects.notes));
|
|
549
551
|
t.section('projects: wsb (Windows Sandbox command line) adapter');
|
|
550
552
|
const id = '12345678-1234-1234-1234-1234567890ab';
|