windows-development-sandbox 1.9.0 → 1.11.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/README.md +64 -17
- package/config.example.json +7 -2
- package/dist/app/features/accounts/accounts.def.d.ts +122 -0
- package/dist/app/features/accounts/accounts.def.js +243 -0
- package/dist/app/features/accounts/accounts.run.d.ts +51 -0
- package/dist/app/features/accounts/accounts.run.js +125 -0
- package/dist/app/features/accounts/index.d.ts +2 -0
- package/dist/app/features/accounts/index.js +3 -0
- package/dist/app/features/agents/agent-entry.d.ts +17 -0
- package/dist/app/features/agents/agent-entry.js +50 -0
- package/dist/app/features/agents/agents.def.d.ts +65 -0
- package/dist/app/features/agents/agents.def.js +142 -0
- package/dist/app/features/agents/agents.run.d.ts +31 -0
- package/dist/app/features/agents/agents.run.js +189 -0
- package/dist/app/features/agents/index.d.ts +3 -0
- package/dist/app/features/agents/index.js +4 -0
- package/dist/app/features/apps/apps-rows.d.ts +31 -0
- package/dist/app/features/apps/apps-rows.js +73 -0
- package/dist/app/features/apps/apps.def.d.ts +181 -0
- package/dist/app/features/apps/apps.def.js +264 -0
- package/dist/app/features/apps/apps.run.d.ts +58 -0
- package/dist/app/features/apps/apps.run.js +76 -0
- package/dist/app/features/apps/index.d.ts +3 -0
- package/dist/app/features/apps/index.js +4 -0
- package/dist/app/features/data/data.def.d.ts +154 -0
- package/dist/app/features/data/data.def.js +201 -0
- package/dist/app/features/data/data.run.d.ts +46 -0
- package/dist/app/features/data/data.run.js +141 -0
- package/dist/app/features/data/index.d.ts +2 -0
- package/dist/app/features/data/index.js +3 -0
- package/dist/app/features/defs.d.ts +952 -4
- package/dist/app/features/defs.js +147 -10
- package/dist/app/features/engine/engine.def.d.ts +228 -0
- package/dist/app/features/engine/engine.def.js +194 -0
- package/dist/app/features/engine/engine.run.d.ts +72 -0
- package/dist/app/features/engine/engine.run.js +77 -0
- package/dist/app/features/engine/index.d.ts +2 -0
- package/dist/app/features/engine/index.js +4 -0
- package/dist/app/features/files/files.def.d.ts +51 -0
- package/dist/app/features/files/files.def.js +38 -0
- package/dist/app/features/files/files.run.d.ts +20 -0
- package/dist/app/features/files/files.run.js +59 -0
- package/dist/app/features/files/index.d.ts +2 -0
- package/dist/app/features/files/index.js +3 -0
- package/dist/app/features/github/github.def.d.ts +80 -0
- package/dist/app/features/github/github.def.js +142 -0
- package/dist/app/features/github/github.run.d.ts +36 -0
- package/dist/app/features/github/github.run.js +59 -0
- package/dist/app/features/github/index.d.ts +2 -0
- package/dist/app/features/github/index.js +3 -0
- package/dist/app/features/health/health.def.d.ts +275 -0
- package/dist/app/features/health/health.def.js +281 -0
- package/dist/app/features/health/health.run.d.ts +125 -0
- package/dist/app/features/health/health.run.js +204 -0
- package/dist/app/features/health/index.d.ts +2 -0
- package/dist/app/features/health/index.js +3 -0
- package/dist/app/features/logs/index.d.ts +2 -0
- package/dist/app/features/logs/index.js +3 -0
- package/dist/app/features/logs/logs.def.d.ts +78 -0
- package/dist/app/features/logs/logs.def.js +115 -0
- package/dist/app/features/logs/logs.run.d.ts +20 -0
- package/dist/app/features/logs/logs.run.js +42 -0
- package/dist/app/features/projects/index.d.ts +2 -0
- package/dist/app/features/projects/index.js +3 -0
- package/dist/app/features/projects/projects.def.d.ts +101 -0
- package/dist/app/features/projects/projects.def.js +208 -0
- package/dist/app/features/projects/projects.run.d.ts +56 -0
- package/dist/app/features/projects/projects.run.js +155 -0
- package/dist/app/features/sandbox/sandbox.def.js +11 -5
- package/dist/app/features/sessions/sessions.def.js +3 -0
- package/dist/app/features/settings/categories.def.js +3 -2
- package/dist/{cli/menu/settings/share.d.ts → app/features/settings/settings-share.d.ts} +1 -1
- package/dist/{cli/menu/settings/share.js → app/features/settings/settings-share.js} +3 -2
- package/dist/app/features/settings/settings.def.d.ts +22 -5
- package/dist/app/features/settings/settings.def.js +81 -6
- package/dist/app/features/settings/settings.run.d.ts +17 -0
- package/dist/app/features/settings/settings.run.js +89 -4
- package/dist/app/features/storage/index.d.ts +2 -0
- package/dist/app/features/storage/index.js +3 -0
- package/dist/app/features/storage/storage.def.d.ts +133 -0
- package/dist/app/features/storage/storage.def.js +225 -0
- package/dist/app/features/storage/storage.run.d.ts +62 -0
- package/dist/app/features/storage/storage.run.js +370 -0
- package/dist/app/features/updates/index.d.ts +3 -0
- package/dist/app/features/updates/index.js +4 -0
- package/dist/app/features/updates/update-lines.d.ts +13 -0
- package/dist/app/features/updates/update-lines.js +61 -0
- package/dist/app/features/updates/updates.def.d.ts +89 -0
- package/dist/app/features/updates/updates.def.js +225 -0
- package/dist/app/features/updates/updates.run.d.ts +48 -0
- package/dist/app/features/updates/updates.run.js +154 -0
- package/dist/app/features/vpn/index.d.ts +2 -0
- package/dist/app/features/vpn/index.js +3 -0
- package/dist/app/features/vpn/vpn.def.d.ts +112 -0
- package/dist/app/features/vpn/vpn.def.js +174 -0
- package/dist/app/features/vpn/vpn.run.d.ts +37 -0
- package/dist/app/features/vpn/vpn.run.js +54 -0
- package/dist/app/features/web/index.d.ts +2 -0
- package/dist/app/features/web/index.js +3 -0
- package/dist/app/features/web/web.def.d.ts +33 -0
- package/dist/app/features/web/web.def.js +90 -0
- package/dist/app/features/web/web.run.d.ts +24 -0
- package/dist/app/features/web/web.run.js +93 -0
- package/dist/app/kernel/define.d.ts +10 -1
- package/dist/app/kernel/io.d.ts +34 -0
- package/dist/app/kernel/io.js +9 -0
- package/dist/app/kernel/rpc.d.ts +17 -0
- package/dist/app/kernel/text.d.ts +2 -0
- package/dist/app/kernel/text.js +7 -0
- package/dist/app/kernel/view.d.ts +24 -1
- package/dist/app/kernel/view.js +1 -1
- package/dist/app/registry.js +74 -1
- package/dist/cli/args.js +1 -1
- package/dist/cli/commands/context.d.ts +7 -0
- package/dist/cli/commands/context.js +29 -2
- package/dist/cli/commands/engine.js +5 -58
- package/dist/cli/commands/github.d.ts +2 -0
- package/dist/cli/commands/github.js +11 -0
- package/dist/cli/commands/index.d.ts +3 -5
- package/dist/cli/commands/index.js +3 -5
- package/dist/cli/commands/launch/launch.js +23 -4
- package/dist/cli/commands/launch/running.js +4 -1
- package/dist/cli/commands/maintenance/config.js +1 -6
- package/dist/cli/commands/maintenance/index.d.ts +0 -1
- package/dist/cli/commands/maintenance/index.js +1 -2
- package/dist/cli/commands/maintenance/logs.js +27 -32
- package/dist/cli/commands/maintenance/migrate.d.ts +0 -8
- package/dist/cli/commands/maintenance/migrate.js +2 -44
- package/dist/cli/commands/maintenance/update.d.ts +0 -19
- package/dist/cli/commands/maintenance/update.js +1 -99
- package/dist/cli/commands/projects/index.d.ts +0 -1
- package/dist/cli/commands/projects/index.js +0 -1
- package/dist/cli/commands/registry.d.ts +1 -1
- package/dist/cli/commands/registry.js +29 -11
- package/dist/cli/commands/repair/checks/data.js +1 -1
- package/dist/cli/commands/repair/checks/hcs.js +28 -1
- package/dist/cli/commands/repair/checks/sandbox.js +1 -1
- package/dist/cli/commands/repair/health-run.d.ts +30 -0
- package/dist/cli/commands/repair/health-run.js +32 -0
- package/dist/cli/commands/repair/printer.d.ts +2 -2
- package/dist/cli/commands/repair/printer.js +2 -11
- package/dist/cli/commands/repair/run.d.ts +1 -21
- package/dist/cli/commands/repair/run.js +13 -70
- package/dist/cli/commands/storage/index.d.ts +0 -1
- package/dist/cli/commands/storage/index.js +0 -1
- package/dist/cli/commands/storage/offer.js +6 -2
- package/dist/cli/commands/vpn.d.ts +1 -3
- package/dist/cli/commands/vpn.js +8 -88
- package/dist/cli/commands/web.d.ts +7 -1
- package/dist/cli/commands/web.js +45 -71
- package/dist/cli/index.js +3 -2
- package/dist/cli/manifest.d.ts +16 -153
- package/dist/cli/manifest.js +20 -50
- package/dist/cli/menu/command-form.js +1 -2
- package/dist/cli/menu/io-menu.d.ts +2 -2
- package/dist/cli/menu/io-menu.js +6 -4
- package/dist/cli/menu/menu.js +1 -1
- package/dist/cli/menu/pages/accounts-page.d.ts +5 -17
- package/dist/cli/menu/pages/accounts-page.js +28 -170
- package/dist/cli/menu/pages/agents-page.d.ts +17 -18
- package/dist/cli/menu/pages/agents-page.js +67 -124
- package/dist/cli/menu/pages/apps-page.d.ts +15 -8
- package/dist/cli/menu/pages/apps-page.js +121 -29
- package/dist/cli/menu/pages/list-page.js +10 -1
- package/dist/cli/menu/pages/maintenance-page.d.ts +51 -52
- package/dist/cli/menu/pages/maintenance-page.js +246 -427
- package/dist/cli/menu/pages/sandbox-page.d.ts +3 -5
- package/dist/cli/menu/pages/sandbox-page.js +34 -112
- package/dist/cli/menu/pages/settings-page.d.ts +21 -3
- package/dist/cli/menu/pages/settings-page.js +89 -17
- package/dist/cli/menu/render-view.js +2 -1
- package/dist/cli/menu/settings/index.d.ts +0 -1
- package/dist/cli/menu/settings/index.js +3 -3
- package/dist/cli/menu/views.js +28 -0
- package/dist/cli/operations/handler.js +7 -3
- package/dist/cli/operations/input.d.ts +1 -1
- package/dist/cli/operations/input.js +29 -5
- package/dist/cli/operations/io-cli.js +9 -1
- package/dist/cli/operations/spec.js +8 -2
- package/dist/cli/output/render-view.js +2 -0
- package/dist/cli/{commands/data/collect.js → services/data-collect.js} +2 -2
- package/dist/cli/{commands/data/remove.js → services/data-remove.js} +2 -2
- package/dist/cli/services/data-service.d.ts +1 -1
- package/dist/cli/services/data-service.js +2 -2
- package/dist/cli/services/databases-service.d.ts +5 -0
- package/dist/cli/services/databases-service.js +15 -0
- package/dist/cli/services/health-service.d.ts +8 -4
- package/dist/cli/services/health-service.js +10 -8
- package/dist/cli/services/index.d.ts +4 -1
- package/dist/cli/services/index.js +4 -1
- package/dist/cli/services/logs-service.d.ts +7 -0
- package/dist/cli/services/logs-service.js +13 -0
- package/dist/cli/services/storage-service.d.ts +19 -0
- package/dist/cli/services/storage-service.js +71 -0
- package/dist/cli/services/vpn-service.d.ts +6 -4
- package/dist/cli/services/vpn-service.js +5 -11
- package/dist/cli/services/web-service.d.ts +4 -3
- package/dist/cli/services/web-service.js +12 -32
- package/dist/core/config/defaults.js +3 -2
- package/dist/core/schema/config.d.ts +6 -0
- package/dist/core/schema/config.js +2 -0
- package/dist/core/schema/github.d.ts +4 -0
- package/dist/core/schema/github.js +7 -0
- package/dist/core/schema/index.d.ts +1 -0
- package/dist/core/schema/index.js +1 -0
- package/dist/core/schema/profile.d.ts +1 -0
- package/dist/core/schema/profile.js +3 -0
- package/dist/core/schema/sandbox.js +3 -3
- package/dist/core/schema/toolchains.js +2 -2
- package/dist/core/schema/vpn.js +1 -1
- package/dist/core/schema/web.d.ts +1 -0
- package/dist/core/schema/web.js +4 -1
- package/dist/core/types.d.ts +6 -3
- package/dist/guest/boot/boot.js +11 -1
- package/dist/guest/daemon/daemon.js +1 -1
- package/dist/guest/daemon/sessions.d.ts +3 -2
- package/dist/guest/daemon/sessions.js +38 -7
- package/dist/guest/governor/core.d.ts +44 -0
- package/dist/guest/governor/core.js +124 -0
- package/dist/guest/governor/decide.d.ts +53 -15
- package/dist/guest/governor/decide.js +155 -72
- package/dist/guest/governor/governor.d.ts +2 -35
- package/dist/guest/governor/governor.js +35 -99
- package/dist/guest/governor/index.d.ts +1 -0
- package/dist/guest/governor/index.js +1 -0
- package/dist/guest/network/firewall.d.ts +3 -0
- package/dist/guest/network/firewall.js +65 -23
- package/dist/guest/runtime/process.js +53 -5
- package/dist/guest/sessions/viewer.js +5 -1
- package/dist/guest/setup/claude-mem.js +12 -4
- package/dist/guest/setup/github-token.d.ts +7 -0
- package/dist/guest/setup/github-token.js +65 -0
- package/dist/guest/toolchains/languages/node.js +40 -4
- package/dist/guest/toolchains/native/rust-extras.js +2 -2
- package/dist/guest/toolchains/tools/cli.d.ts +8 -0
- package/dist/guest/toolchains/tools/cli.js +16 -2
- package/dist/guest/vpn/openvpn.d.ts +5 -0
- package/dist/guest/vpn/openvpn.js +14 -1
- package/dist/guest/vpn/vpn.js +55 -16
- package/dist/guest/vpn/wireguard.js +2 -0
- package/dist/host/channel/attach.d.ts +1 -0
- package/dist/host/channel/attach.js +1 -0
- package/dist/host/channel/channel.d.ts +1 -1
- package/dist/host/channel/channel.js +2 -2
- package/dist/host/engines/hcs/check.d.ts +1 -0
- package/dist/host/engines/hcs/check.js +1 -1
- package/dist/host/engines/hcs/engine.d.ts +1 -1
- package/dist/host/engines/hcs/engine.js +6 -4
- package/dist/host/engines/hcs/helper.d.ts +11 -0
- package/dist/host/engines/hcs/helper.js +31 -2
- package/dist/host/engines/hcs/leftovers.d.ts +42 -0
- package/dist/host/engines/hcs/leftovers.js +101 -0
- package/dist/host/engines/index.d.ts +1 -0
- package/dist/host/engines/index.js +1 -0
- package/dist/host/github/deliver.d.ts +13 -0
- package/dist/host/github/deliver.js +51 -0
- package/dist/host/github/index.d.ts +2 -0
- package/dist/host/github/index.js +3 -0
- package/dist/host/github/token.d.ts +21 -0
- package/dist/host/github/token.js +74 -0
- package/dist/host/launch/generate.js +11 -5
- package/dist/host/launch/index.d.ts +1 -1
- package/dist/host/launch/index.js +1 -1
- package/dist/host/launch/session-file.js +1 -2
- package/dist/host/launch/wsb-file.d.ts +11 -7
- package/dist/host/launch/wsb-file.js +30 -12
- package/dist/host/life/host-memory.d.ts +1 -0
- package/dist/host/life/host-memory.js +4 -1
- package/dist/host/life/watchdog.d.ts +11 -0
- package/dist/host/life/watchdog.js +36 -4
- package/dist/host/sandbox/tasklist.d.ts +6 -0
- package/dist/host/sandbox/tasklist.js +37 -0
- package/dist/host/secrets/launch-secrets.d.ts +2 -1
- package/dist/host/secrets/launch-secrets.js +4 -2
- package/dist/host/vpn/status.js +13 -3
- package/dist/host/web/backend.d.ts +1 -3
- package/dist/host/web/index.d.ts +2 -1
- package/dist/host/web/index.js +2 -1
- package/dist/host/web/live.d.ts +23 -0
- package/dist/host/web/live.js +107 -0
- package/dist/host/web/rpc.d.ts +6 -1
- package/dist/host/web/rpc.js +23 -31
- package/dist/host/web/runner.d.ts +4 -0
- package/dist/host/web/runner.js +12 -1
- package/dist/host/web/server.d.ts +30 -2
- package/dist/host/web/server.js +87 -29
- package/dist/host/web/state.d.ts +1 -0
- package/dist/host/web/state.js +2 -0
- package/dist/runtime/agent.js +44 -16
- package/dist/runtime/daemon.js +1154 -857
- package/dist/runtime/db.js +44 -16
- package/dist/runtime/main.js +532 -115
- package/dist/runtime/netproxy.js +34 -9
- package/dist/runtime/view.js +499 -149
- package/dist/selftest/app.test.js +620 -12
- package/dist/selftest/channel.test.js +18 -1
- package/dist/selftest/cli.test.js +1 -1
- package/dist/selftest/config.test.js +1 -1
- package/dist/selftest/contained.test.js +1 -1
- package/dist/selftest/data.test.js +1 -2
- package/dist/selftest/engine.test.js +3 -1
- package/dist/selftest/github.test.d.ts +2 -0
- package/dist/selftest/github.test.js +243 -0
- package/dist/selftest/guest-boot.test.js +47 -1
- package/dist/selftest/hcs.test.js +105 -8
- package/dist/selftest/health.test.js +71 -0
- package/dist/selftest/heavy-load.test.js +152 -66
- package/dist/selftest/index.js +4 -0
- package/dist/selftest/layout.test.js +8 -0
- package/dist/selftest/live-terminal.test.js +74 -0
- package/dist/selftest/menu-screens.js +171 -56
- package/dist/selftest/menu.test.js +54 -37
- package/dist/selftest/migrate.test.js +14 -12
- package/dist/selftest/network.test.js +20 -1
- package/dist/selftest/powershell-variables.test.d.ts +2 -0
- package/dist/selftest/powershell-variables.test.js +61 -0
- package/dist/selftest/support/engine-golden.js +1 -0
- package/dist/selftest/support/fixtures.d.ts +5 -0
- package/dist/selftest/support/web-preview.d.ts +1 -0
- package/dist/selftest/support/web-preview.js +856 -0
- package/dist/selftest/update-service.test.js +15 -8
- package/dist/selftest/vpn.test.js +86 -2
- package/dist/selftest/web.test.js +58 -11
- package/dist/shared/channel/run-dir.d.ts +2 -0
- package/dist/shared/channel/run-dir.js +3 -0
- package/dist/shared/channel/schema.d.ts +7 -0
- package/dist/shared/channel/schema.js +9 -1
- package/dist/shared/channel/secrets.d.ts +1 -0
- package/dist/shared/channel/secrets.js +3 -0
- package/dist/shared/github/index.d.ts +1 -0
- package/dist/shared/github/index.js +2 -0
- package/dist/shared/github/token.d.ts +29 -0
- package/dist/shared/github/token.js +89 -0
- package/dist/shared/io/copy-tree.d.ts +7 -0
- package/dist/shared/io/copy-tree.js +45 -0
- package/dist/shared/io/index.d.ts +2 -0
- package/dist/shared/io/index.js +2 -0
- package/dist/shared/io/robocopy-result.d.ts +6 -0
- package/dist/shared/io/robocopy-result.js +23 -0
- package/dist/shared/memory/policy.d.ts +38 -12
- package/dist/shared/memory/policy.js +58 -19
- package/dist/shared/network/firewall-rules.d.ts +8 -0
- package/dist/shared/network/firewall-rules.js +28 -0
- package/dist/shared/pty/ctrl-c.d.ts +18 -0
- package/dist/shared/pty/ctrl-c.js +36 -0
- package/dist/shared/pty/index.d.ts +1 -0
- package/dist/shared/pty/index.js +1 -0
- package/dist/shared/pty/terminal.d.ts +2 -0
- package/dist/shared/pty/terminal.js +21 -2
- package/dist/shared/vpn/kill-switch.d.ts +13 -2
- package/dist/shared/vpn/kill-switch.js +88 -8
- package/dist/shared/web/protocol.d.ts +0 -4
- package/dist/sync/watcher.js +1 -1
- package/dist/web/index.html +2 -2
- package/dist/web/{main-T5DMCHYV.css → main-6JF3ASB5.css} +1 -1
- package/dist/web/main-Z645W45E.js +219 -0
- package/native/csharp/HcsHost/AssemblyInfo.cs +3 -3
- package/native/csharp/HostTools/AssemblyInfo.cs +3 -3
- package/native/csharp/HostTools/MemoryStatus.cs +128 -107
- package/native/scripts/memory-status.ps1 +10 -2
- package/package.json +10 -3
- package/sandbox/csharp/MemGov.cs +668 -398
- package/sandbox/csharp/PtyHost.cs +104 -15
- package/sandbox/csharp/SandboxTools/CpuCap.cs +50 -1
- package/sandbox/csharp/SandboxTools/Program.cs +1 -1
- package/sandbox/scripts/new-shortcuts.ps1 +3 -1
- package/sandbox/scripts/repair-wmi-services.ps1 +26 -0
- package/schemas/config.schema.json +25 -7
- package/schemas/sandbox-config.schema.json +7 -3
- package/dist/cli/commands/accounts.d.ts +0 -2
- package/dist/cli/commands/accounts.js +0 -96
- package/dist/cli/commands/data/clean.d.ts +0 -3
- package/dist/cli/commands/data/clean.js +0 -60
- package/dist/cli/commands/data/index.d.ts +0 -4
- package/dist/cli/commands/data/index.js +0 -62
- package/dist/cli/commands/maintenance/clean.d.ts +0 -2
- package/dist/cli/commands/maintenance/clean.js +0 -24
- package/dist/cli/commands/maintenance/config-share.d.ts +0 -12
- package/dist/cli/commands/maintenance/config-share.js +0 -80
- package/dist/cli/commands/projects/projects.d.ts +0 -2
- package/dist/cli/commands/projects/projects.js +0 -162
- package/dist/cli/commands/storage/contained.d.ts +0 -3
- package/dist/cli/commands/storage/contained.js +0 -179
- package/dist/cli/commands/storage/storage.d.ts +0 -8
- package/dist/cli/commands/storage/storage.js +0 -179
- package/dist/cli/menu/add-agent.d.ts +0 -47
- package/dist/cli/menu/add-agent.js +0 -168
- package/dist/cli/menu/apps.d.ts +0 -69
- package/dist/cli/menu/apps.js +0 -214
- package/dist/cli/menu/data-folder.d.ts +0 -18
- package/dist/cli/menu/data-folder.js +0 -99
- package/dist/cli/menu/share-settings.d.ts +0 -21
- package/dist/cli/menu/share-settings.js +0 -112
- package/dist/cli/menu/vpn-login.d.ts +0 -16
- package/dist/cli/menu/vpn-login.js +0 -74
- package/dist/web/main-NRRS5O6Z.js +0 -157
- /package/dist/cli/{commands/data/collect.d.ts → services/data-collect.d.ts} +0 -0
- /package/dist/cli/{commands/data/remove.d.ts → services/data-remove.d.ts} +0 -0
|
@@ -4,9 +4,8 @@ import fs from 'node:fs';
|
|
|
4
4
|
import path from 'node:path';
|
|
5
5
|
import { Draft } from '../cli/menu/settings/draft.js';
|
|
6
6
|
import { ConfigFile } from '../app/features/settings/index.js';
|
|
7
|
-
import { AppsModel } from '../cli/menu/apps.js';
|
|
8
7
|
import { accountsOptions } from '../cli/menu/pages/accounts-page.js';
|
|
9
|
-
import { appsOptions } from '../cli/menu/pages/apps-page.js';
|
|
8
|
+
import { appsOptions, stageTicks } from '../cli/menu/pages/apps-page.js';
|
|
10
9
|
import { maintenanceOptions } from '../cli/menu/pages/maintenance-page.js';
|
|
11
10
|
import { sandboxOptions } from '../cli/menu/pages/sandbox-page.js';
|
|
12
11
|
import { sessionsOptions } from '../cli/menu/pages/sessions-page.js';
|
|
@@ -23,7 +22,7 @@ export const SIZES = [
|
|
|
23
22
|
];
|
|
24
23
|
const NOW = Date.now();
|
|
25
24
|
const API_FOLDER = 'C:\\Projects\\api';
|
|
26
|
-
/** The Data folder row of General (in the menu it comes from
|
|
25
|
+
/** The Data folder row of General (in the menu it comes from settings-page.ts). */
|
|
27
26
|
const DATA_FOLDER_ROW = [
|
|
28
27
|
{
|
|
29
28
|
value: '@data-folder',
|
|
@@ -34,18 +33,25 @@ const DATA_FOLDER_ROW = [
|
|
|
34
33
|
},
|
|
35
34
|
];
|
|
36
35
|
const ACCOUNTS = {
|
|
36
|
+
agent: 'claude',
|
|
37
37
|
agents: [
|
|
38
|
-
{
|
|
39
|
-
|
|
40
|
-
|
|
38
|
+
{
|
|
39
|
+
name: 'claude',
|
|
40
|
+
kept: true,
|
|
41
|
+
canSavePc: true,
|
|
42
|
+
accounts: [
|
|
43
|
+
{ name: 'work', email: 'me@work.example', isDefault: true, isActive: true, savedAt: '2026-10-13T09:30:00Z' },
|
|
44
|
+
{ name: 'home', email: null, isDefault: false, isActive: false, savedAt: '2026-10-01T18:00:00Z' },
|
|
45
|
+
],
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
name: 'codex',
|
|
49
|
+
kept: true,
|
|
50
|
+
canSavePc: true,
|
|
51
|
+
accounts: [{ name: 'main', email: null, isDefault: true, isActive: false, savedAt: '2026-10-12T08:00:00Z' }],
|
|
52
|
+
},
|
|
53
|
+
{ name: 'opencode', kept: false, canSavePc: false, accounts: [] },
|
|
41
54
|
],
|
|
42
|
-
rows: {
|
|
43
|
-
claude: [
|
|
44
|
-
{ name: 'work', email: 'me@work.example', isDefault: true, isActive: true, savedAt: '2026-10-13T09:30:00Z' },
|
|
45
|
-
{ name: 'home', email: null, isDefault: false, isActive: false, savedAt: '2026-10-01T18:00:00Z' },
|
|
46
|
-
],
|
|
47
|
-
codex: [{ name: 'main', email: null, isDefault: true, isActive: false, savedAt: '2026-10-12T08:00:00Z' }],
|
|
48
|
-
},
|
|
49
55
|
};
|
|
50
56
|
const SESSIONS = [
|
|
51
57
|
{
|
|
@@ -164,54 +170,163 @@ export function renderScreens(dir) {
|
|
|
164
170
|
};
|
|
165
171
|
const maintenance = {
|
|
166
172
|
data: {
|
|
173
|
+
dataPath: 'C:\\AgentData',
|
|
174
|
+
storageRoot: 'C:\\ProgramData\\AgentSandbox\\users\\me',
|
|
175
|
+
totalBytes: 8.9e9,
|
|
176
|
+
total: '8.9 GB',
|
|
177
|
+
storageShare: '<- sandbox storage (8.9 GB of it)',
|
|
178
|
+
areaTotals: { tools: '7.1 GB', state: '1.8 GB', host: '4.0 KB' },
|
|
167
179
|
entries: [
|
|
168
|
-
{
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
180
|
+
{
|
|
181
|
+
area: 'tools',
|
|
182
|
+
name: 'rust',
|
|
183
|
+
path: 'C:\\AgentData\\tools\\rust',
|
|
184
|
+
bytes: 4.6e9,
|
|
185
|
+
size: '4.6 GB',
|
|
186
|
+
target: 'tools/rust',
|
|
187
|
+
},
|
|
188
|
+
{
|
|
189
|
+
area: 'tools',
|
|
190
|
+
name: 'vscode',
|
|
191
|
+
path: 'C:\\AgentData\\tools\\vscode',
|
|
192
|
+
bytes: 2.5e9,
|
|
193
|
+
size: '2.5 GB',
|
|
194
|
+
target: 'tools/vscode',
|
|
195
|
+
},
|
|
196
|
+
{
|
|
197
|
+
area: 'state',
|
|
198
|
+
name: 'state/claude',
|
|
199
|
+
path: 'C:\\AgentData\\state\\claude',
|
|
200
|
+
bytes: 1.8e9,
|
|
201
|
+
size: '1.8 GB',
|
|
202
|
+
target: 'state/claude',
|
|
203
|
+
},
|
|
204
|
+
{
|
|
205
|
+
area: 'host',
|
|
206
|
+
name: 'accounts',
|
|
207
|
+
path: 'C:\\Users\\me\\AppData\\Local\\AgentSandbox\\accounts',
|
|
208
|
+
bytes: 4096,
|
|
209
|
+
size: '4.0 KB',
|
|
210
|
+
target: null,
|
|
211
|
+
},
|
|
212
|
+
],
|
|
213
|
+
disks: [
|
|
214
|
+
{
|
|
215
|
+
drive: 'C:\\',
|
|
216
|
+
totalBytes: 40e9,
|
|
217
|
+
freeBytes: 22e9,
|
|
218
|
+
usedBytes: 18e9,
|
|
219
|
+
holdsStorage: true,
|
|
220
|
+
used: '18 GB',
|
|
221
|
+
usedPercent: 45,
|
|
222
|
+
free: '22 GB',
|
|
223
|
+
total: '40 GB',
|
|
224
|
+
},
|
|
172
225
|
],
|
|
173
|
-
disks: [{ drive: 'C:\\', totalBytes: 40e9, freeBytes: 22e9, usedBytes: 18e9, holdsStorage: true }],
|
|
174
|
-
total: 8.9e9,
|
|
175
226
|
},
|
|
176
|
-
logs:
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
227
|
+
logs: {
|
|
228
|
+
folder: 'C:\\AgentData\\logs',
|
|
229
|
+
files: [
|
|
230
|
+
{
|
|
231
|
+
name: 'guest-2026-10-14.log',
|
|
232
|
+
path: 'C:\\AgentData\\logs\\guest-2026-10-14.log',
|
|
233
|
+
bytes: 120000,
|
|
234
|
+
modified: NOW - 60000,
|
|
235
|
+
},
|
|
236
|
+
{
|
|
237
|
+
name: 'daemon-2026-10-14.log',
|
|
238
|
+
path: 'C:\\AgentData\\logs\\daemon-2026-10-14.log',
|
|
239
|
+
bytes: 8000,
|
|
240
|
+
modified: NOW - 600000,
|
|
241
|
+
},
|
|
242
|
+
],
|
|
243
|
+
crash: true,
|
|
244
|
+
},
|
|
245
|
+
health: {
|
|
246
|
+
last: {
|
|
247
|
+
at: new Date(NOW - 180000).toISOString(),
|
|
248
|
+
mode: 'check',
|
|
249
|
+
checks: [
|
|
250
|
+
{ id: 'config', group: 'Settings', name: 'Config file', status: 'ok', detail: 'valid', fixable: false },
|
|
251
|
+
{
|
|
252
|
+
id: 'stale',
|
|
253
|
+
group: 'Data folder',
|
|
254
|
+
name: 'Stale run folders',
|
|
255
|
+
status: 'fixed',
|
|
256
|
+
detail: 'removed 2',
|
|
257
|
+
fixable: false,
|
|
258
|
+
},
|
|
259
|
+
{
|
|
260
|
+
id: 'cache',
|
|
261
|
+
group: 'Sandbox',
|
|
262
|
+
name: 'Toolchain cache',
|
|
263
|
+
status: 'needs-you',
|
|
264
|
+
detail: 'close the sandbox first',
|
|
265
|
+
fixable: false,
|
|
266
|
+
},
|
|
267
|
+
],
|
|
268
|
+
summary: { total: 3, ok: 1, fixed: 1, warn: 0, needsYou: 1, skipped: 0, fixable: 0 },
|
|
269
|
+
details: [
|
|
270
|
+
['Windows Sandbox', 'available'],
|
|
271
|
+
['Config file', 'C:\\Users\\me\\.agent-sandbox\\config.json'],
|
|
272
|
+
],
|
|
273
|
+
setup: {
|
|
274
|
+
checks: [
|
|
275
|
+
{ name: 'Windows edition', status: 'ok', detail: 'Pro' },
|
|
276
|
+
{ name: 'Windows Sandbox feature', status: 'action', detail: 'turned off' },
|
|
277
|
+
],
|
|
278
|
+
canEnable: true,
|
|
279
|
+
error: null,
|
|
280
|
+
},
|
|
281
|
+
log: null,
|
|
282
|
+
},
|
|
283
|
+
},
|
|
284
|
+
storage: {
|
|
285
|
+
show: {
|
|
286
|
+
root: 'C:\\ProgramData\\AgentSandbox\\users\\me',
|
|
287
|
+
exists: true,
|
|
288
|
+
holdsData: true,
|
|
289
|
+
measured: null,
|
|
290
|
+
size: 'not measured yet',
|
|
291
|
+
defaultRoot: 'C:\\ProgramData\\AgentSandbox\\users\\me',
|
|
292
|
+
defaultInUse: true,
|
|
293
|
+
otherFoldersWithData: [],
|
|
294
|
+
},
|
|
295
|
+
contained: {
|
|
296
|
+
setting: 'off',
|
|
297
|
+
maxGb: 60,
|
|
298
|
+
available: true,
|
|
299
|
+
reasons: [],
|
|
300
|
+
fixes: [],
|
|
301
|
+
image: 'C:\\ProgramData\\AgentSandbox\\users\\me\\contained\\agent.vhdx',
|
|
302
|
+
imageExists: false,
|
|
303
|
+
imageBytes: null,
|
|
304
|
+
mountFolder: 'C:\\ProgramData\\AgentSandbox\\users\\me\\mount',
|
|
305
|
+
recordedMounted: false,
|
|
306
|
+
holders: 0,
|
|
307
|
+
mountedNow: null,
|
|
308
|
+
},
|
|
194
309
|
},
|
|
195
310
|
updates: {
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
311
|
+
status: {
|
|
312
|
+
managed: true,
|
|
313
|
+
version: '1.4.3',
|
|
314
|
+
scope: 'user',
|
|
315
|
+
autoUpdate: true,
|
|
316
|
+
autoOffText: null,
|
|
202
317
|
previous: '1.4.2',
|
|
203
|
-
failed: { version: '1.4.4',
|
|
318
|
+
failed: { version: '1.4.4', reason: 'it did not start' },
|
|
319
|
+
npmCommand: 'npm install -g windows-development-sandbox',
|
|
320
|
+
error: null,
|
|
321
|
+
settings: {
|
|
322
|
+
pending: ['2026-10-unpin-config-defaults: stop pinning old defaults in your config.json'],
|
|
323
|
+
error: null,
|
|
324
|
+
},
|
|
204
325
|
},
|
|
326
|
+
latest: '1.5.0',
|
|
205
327
|
},
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
facts: {},
|
|
209
|
-
canEnable: true,
|
|
210
|
-
checks: [
|
|
211
|
-
{ name: 'Windows edition', status: 'ok', detail: 'Pro' },
|
|
212
|
-
{ name: 'Windows Sandbox feature', status: 'action', detail: 'turned off' },
|
|
213
|
-
],
|
|
214
|
-
},
|
|
328
|
+
engine: null,
|
|
329
|
+
web: { running: true, port: 47800, address: 'http://127.0.0.1:47800/' },
|
|
215
330
|
more: [
|
|
216
331
|
{ name: 'sync', summary: 'sync history now' },
|
|
217
332
|
{ name: 'audit', summary: 'show what the sandbox did' },
|
|
@@ -225,9 +340,9 @@ export function renderScreens(dir) {
|
|
|
225
340
|
draft.stage(user, harness.key, 'codex');
|
|
226
341
|
if (flag)
|
|
227
342
|
draft.stage(user, flag.key, !user.userConfig()[flag.key[0]]);
|
|
228
|
-
const
|
|
343
|
+
const appsData = path.join(dir, 'data');
|
|
229
344
|
const appsDraft = new Draft();
|
|
230
|
-
|
|
345
|
+
stageTicks(user, appsDraft, ['git-gui']);
|
|
231
346
|
const out = [];
|
|
232
347
|
for (const size of SIZES) {
|
|
233
348
|
const agentsModel = {
|
|
@@ -249,7 +364,7 @@ export function renderScreens(dir) {
|
|
|
249
364
|
out.push(block('3 Sandbox (stopped) · ' + category, draw(2, { ...sandboxOptions(stopped), startCategory: category }, size), size));
|
|
250
365
|
for (const category of ['status', 'projects', 'databases'])
|
|
251
366
|
out.push(block('3 Sandbox · ' + category, draw(2, { ...sandboxOptions(sandbox), startCategory: category }, size, status), size));
|
|
252
|
-
out.push(block('4 Apps (1 unsaved)', draw(3, appsOptions(
|
|
367
|
+
out.push(block('4 Apps (1 unsaved)', draw(3, appsOptions(user, appsData, appsDraft, 'user'), size, status, appsDraft.count()), size));
|
|
253
368
|
for (const category of CATEGORIES)
|
|
254
369
|
out.push(block('5 Settings · ' + category.label + ' (2 unsaved)', draw(4, { ...settingsOptions(files, 'user', draft, DATA_FOLDER_ROW), startCategory: category.id }, size, status, draft.count()), size));
|
|
255
370
|
// The leave dialog over the settings screen.
|
|
@@ -5,19 +5,21 @@ import fs from 'node:fs';
|
|
|
5
5
|
import { CATEGORIES, ConfigFile, SETTINGS_ELSEWHERE } from '../app/features/settings/index.js';
|
|
6
6
|
import { Draft } from '../cli/menu/settings/draft.js';
|
|
7
7
|
import { z } from 'zod';
|
|
8
|
-
import {
|
|
9
|
-
import { APP_GROUPS,
|
|
8
|
+
import { addedAgents, agentNameProblem, commandFromPackage, newAgent } from '../app/features/agents/index.js';
|
|
9
|
+
import { APP_GROUPS, appRows, REQUEST_APP, requestAppUrl } from '../app/features/apps/index.js';
|
|
10
|
+
import { appsCategories, appsItems } from '../cli/menu/pages/apps-page.js';
|
|
10
11
|
import { readMenuView, saveMenuView } from '../cli/menu/memory.js';
|
|
11
12
|
import path from 'node:path';
|
|
12
13
|
import { argPathKind, optionLabel, optionPathKind, plainDescription } from '../cli/menu/command-fields.js';
|
|
13
14
|
import { CommandForm } from '../cli/menu/command-form.js';
|
|
14
15
|
import { COMMANDS, commandSpec } from '../cli/manifest.js';
|
|
15
16
|
import { accountsOptions } from '../cli/menu/pages/accounts-page.js';
|
|
16
|
-
import {
|
|
17
|
+
import { agentCategories, agentsHaveStagedChanges, agentsOptions, hostAgentsToShow, startArgv, } from '../cli/menu/pages/agents-page.js';
|
|
17
18
|
import { ListPage } from '../cli/menu/pages/list-page.js';
|
|
18
19
|
import { sandboxOptions } from '../cli/menu/pages/sandbox-page.js';
|
|
19
20
|
import { sessionsOptions } from '../cli/menu/pages/sessions-page.js';
|
|
20
|
-
import { pathKindOf, SchemaNode } from '../app/kernel/index.js';
|
|
21
|
+
import { fakeIO, pathKindOf, SchemaNode } from '../app/kernel/index.js';
|
|
22
|
+
import { runDefinition } from '../app/registry.js';
|
|
21
23
|
import { numberProblem, ValueEditor } from '../cli/menu/settings/value-editor.js';
|
|
22
24
|
import { APP_CATEGORIES } from '../shared/apps/index.js';
|
|
23
25
|
import { settingsOf, settingsOptions } from '../cli/menu/pages/settings-page.js';
|
|
@@ -266,15 +268,11 @@ export const menuSuite = {
|
|
|
266
268
|
], 'a new agent name is checked (letters, no duplicates); the command is guessed from the package');
|
|
267
269
|
const agentFile = ConfigFile.user(t.at('agents', 'config.json'));
|
|
268
270
|
t.write(agentFile.file, '{\n // mine\n "defaultHarness": "claude"\n}\n');
|
|
269
|
-
const
|
|
270
|
-
|
|
271
|
-
text: () => Promise.resolve(answers.shift()),
|
|
272
|
-
pickPath: () => Promise.resolve(answers.shift()),
|
|
273
|
-
});
|
|
274
|
-
const added = await new AddAgent(typed('npm', 'my-agent', '@me/my-agent@latest', 'my-agent'), agentFile, new Draft(), ['claude', 'codex']).run();
|
|
271
|
+
const agentCtx = { loaded: { configPath: agentFile.file } };
|
|
272
|
+
const added = (await runDefinition('agents.add', agentCtx, {}, fakeIO(['npm', 'my-agent', '@me/my-agent@latest', 'my-agent']).io));
|
|
275
273
|
const saved = agentFile.userConfig().harnesses['my-agent'];
|
|
276
|
-
t.check(added
|
|
277
|
-
added.
|
|
274
|
+
t.check(added.name === 'my-agent' &&
|
|
275
|
+
added.message === 'Added my-agent.' &&
|
|
278
276
|
saved?.npmPackage === '@me/my-agent@latest' &&
|
|
279
277
|
saved.npmBin === 'my-agent' &&
|
|
280
278
|
agentFile.text().includes('// mine') &&
|
|
@@ -284,9 +282,7 @@ export const menuSuite = {
|
|
|
284
282
|
...agentFile.valueInFile(['harnesses']),
|
|
285
283
|
other: newAgent('uv', 'tool', 'tool'),
|
|
286
284
|
});
|
|
287
|
-
|
|
288
|
-
t.check(joined?.saved === false &&
|
|
289
|
-
Object.keys(stagedAgents.value(agentFile, ['harnesses'])).join() === 'my-agent,other,third', 'with unsaved changes to the agents, the new agent joins them instead of being written');
|
|
285
|
+
t.check(agentsHaveStagedChanges(agentFile, stagedAgents) && !agentsHaveStagedChanges(agentFile, new Draft()), 'with unsaved changes to the agents, the menu asks to save them first (the agent operations wait)');
|
|
290
286
|
t.section('list keys follow the highlighted entry');
|
|
291
287
|
const keyList = new ListScreen({
|
|
292
288
|
path: [],
|
|
@@ -344,6 +340,30 @@ export const menuSuite = {
|
|
|
344
340
|
.body.map((l) => Text.strip(l))
|
|
345
341
|
.find((l) => l.includes('›'));
|
|
346
342
|
t.check(marked?.includes('Beta') === true, 'a section opens with the cursor on the entry it asks for');
|
|
343
|
+
class Broken extends ListPage {
|
|
344
|
+
label = 'Broken';
|
|
345
|
+
load() {
|
|
346
|
+
return Promise.resolve();
|
|
347
|
+
}
|
|
348
|
+
options() {
|
|
349
|
+
return { path: [], items: [{ value: 'a', label: 'Alpha' }] };
|
|
350
|
+
}
|
|
351
|
+
act() {
|
|
352
|
+
return Promise.reject(new Error('the action broke'));
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
const broken = new Broken(new App());
|
|
356
|
+
await broken.open();
|
|
357
|
+
let survived = true;
|
|
358
|
+
try {
|
|
359
|
+
await broken.handle(press('return'));
|
|
360
|
+
}
|
|
361
|
+
catch {
|
|
362
|
+
survived = false;
|
|
363
|
+
}
|
|
364
|
+
const brokenFrame = broken.render({ width: 100, height: 12 });
|
|
365
|
+
const brokenScreen = Text.strip([...brokenFrame.body, brokenFrame.notice ?? ''].join('\n'));
|
|
366
|
+
t.check(survived && brokenScreen.includes('the action broke'), 'an action that fails shows its problem in the menu instead of closing it', brokenScreen);
|
|
347
367
|
t.section('proper inputs');
|
|
348
368
|
const user2 = ConfigFile.user(t.at('inputs', 'config.json'));
|
|
349
369
|
const leaf = (...key) => {
|
|
@@ -549,9 +569,10 @@ export const menuSuite = {
|
|
|
549
569
|
hostAgents: [],
|
|
550
570
|
removable: addedAgents(['claude', 'codex', 'mine']),
|
|
551
571
|
};
|
|
552
|
-
const startActions = agentActions(actionModel);
|
|
553
|
-
const keyFor = (key, id) => startActions.find((a) => a.key === key)?.applies?.(id) ?? false;
|
|
554
572
|
const actionList = agentsOptions(actionModel, 'C:\\code\\api');
|
|
573
|
+
const keyFor = (key, id) => (typeof actionList.actions === 'function' ? actionList.actions('start') : [])
|
|
574
|
+
.find((a) => a.key === key)
|
|
575
|
+
?.applies?.(id) ?? false;
|
|
555
576
|
t.check(JSON.stringify(actionModel.removable) === '["mine"]' &&
|
|
556
577
|
keyFor('d', 'agent:codex') &&
|
|
557
578
|
!keyFor('d', 'agent:claude') &&
|
|
@@ -563,20 +584,15 @@ export const menuSuite = {
|
|
|
563
584
|
actionList.actions('options').length === 0, 'Make default shows on any other agent, Remove only on one you added; neither on built-in agents or other rows');
|
|
564
585
|
const agentsFile = ConfigFile.user(t.at('agents-actions', 'config.json'));
|
|
565
586
|
t.write(agentsFile.file, '{\n // mine\n "defaultHarness": "claude"\n}\n');
|
|
566
|
-
const
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
const answers = ['mine', '@me/mine@latest', 'mine'];
|
|
571
|
-
return () => Promise.resolve(answers.shift());
|
|
572
|
-
})(),
|
|
573
|
-
}, agentsFile, agentDraft, ['claude']).run();
|
|
574
|
-
makeDefaultAgent(agentsFile, agentDraft, 'mine');
|
|
587
|
+
const agentsCtx = { loaded: { configPath: agentsFile.file } };
|
|
588
|
+
const quiet = (answers = []) => fakeIO(answers).io;
|
|
589
|
+
await runDefinition('agents.add', agentsCtx, {}, quiet(['npm', 'mine', '@me/mine@latest', 'mine']));
|
|
590
|
+
await runDefinition('agents.makeDefault', agentsCtx, { name: 'mine' }, quiet());
|
|
575
591
|
const becameDefault = agentsFile.userConfig().defaultHarness;
|
|
576
|
-
await t.throws(() =>
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
await t.throws(() =>
|
|
592
|
+
await t.throws(() => runDefinition('agents.remove', agentsCtx, { name: 'mine' }, quiet([true])), 'default agent', 'the default agent is not removed');
|
|
593
|
+
await runDefinition('agents.makeDefault', agentsCtx, { name: 'codex' }, quiet());
|
|
594
|
+
await runDefinition('agents.remove', agentsCtx, { name: 'mine' }, quiet([true]));
|
|
595
|
+
await t.throws(() => runDefinition('agents.remove', agentsCtx, { name: 'claude' }, quiet([true])), 'built in', 'a built-in agent is not removed');
|
|
580
596
|
t.check(becameDefault === 'mine' &&
|
|
581
597
|
agentsFile.userConfig().defaultHarness === 'codex' &&
|
|
582
598
|
!agentsFile.text().includes('mine"') &&
|
|
@@ -600,18 +616,19 @@ export const menuSuite = {
|
|
|
600
616
|
stoppedItems.some((i) => i.value === 'act:start' && i.category === 'databases') &&
|
|
601
617
|
stoppedItems.some((i) => i.value === '@add-root') &&
|
|
602
618
|
!stoppedItems.some((i) => i.value === 'act:stop'), 'with no sandbox running, Sandbox offers to start one (Status and Databases) instead of dead rows');
|
|
603
|
-
const noLogins = accountsOptions({
|
|
619
|
+
const noLogins = accountsOptions({
|
|
620
|
+
agent: 'claude',
|
|
621
|
+
agents: [{ name: 'claude', kept: true, canSavePc: true, accounts: [] }],
|
|
622
|
+
});
|
|
604
623
|
t.equal(noLogins.items.map((i) => i.value), ['@save-sandbox', '@save-pc'], 'with no saved login, Accounts offers to save the sandbox login or this PC login (Enter)');
|
|
605
624
|
t.section('apps in a few groups');
|
|
606
|
-
const
|
|
607
|
-
const
|
|
608
|
-
const appItems = appsUser.items(new Draft()).filter((i) => i.value !== REQUEST_APP);
|
|
625
|
+
const groupIds = appsCategories(user2).map((c) => c.id);
|
|
626
|
+
const appItems = appsItems(user2, t.dir('apps-groups'), new Draft()).filter((i) => i.value !== REQUEST_APP);
|
|
609
627
|
t.check(groupIds.length <= 6 &&
|
|
610
|
-
|
|
611
|
-
5 &&
|
|
628
|
+
appsCategories(ConfigFile.project(t.dir('apps-groups', 'project'))).length <= 5 &&
|
|
612
629
|
APP_GROUPS.every((g) => appItems.some((i) => i.category === g.id)) &&
|
|
613
630
|
appItems.every((i) => groupIds.includes(i.category ?? '')) &&
|
|
614
|
-
appItems.length ===
|
|
631
|
+
appItems.length === appRows(user2, t.dir('apps-groups')).length &&
|
|
615
632
|
APP_CATEGORIES.every((c) => APP_GROUPS.some((g) => g.members.includes(c.id))), 'the apps are in at most 6 groups; every catalogue category belongs to one and every app is listed', groupIds.join());
|
|
616
633
|
t.section('dialog box');
|
|
617
634
|
const box = dialogBox({ title: 'Unsaved changes', lines: ['You have 2 unsaved changes.'], buttons: 'Save' }, 61);
|
|
@@ -6,7 +6,8 @@ import { parse } from 'jsonc-parser';
|
|
|
6
6
|
import { DEFAULTS, loadConfig, machineConfigPath } from '../core/config/index.js';
|
|
7
7
|
import { MIGRATIONS, MigrationBackup, MigrationMarker, MigrationRunner, } from '../host/migrate/index.js';
|
|
8
8
|
import { DEFAULTS_SNAPSHOTS } from '../host/migrate/snapshots.js';
|
|
9
|
-
import {
|
|
9
|
+
import { migrateWith } from '../app/features/updates/updates.run.js';
|
|
10
|
+
import { fakeIO } from '../app/kernel/index.js';
|
|
10
11
|
import { autoMigrates, continuesAfterFailedMigration, MigrateService } from '../cli/services/index.js';
|
|
11
12
|
const readText = (file) => fs.readFileSync(file, 'utf8');
|
|
12
13
|
export const migrateSuite = {
|
|
@@ -163,26 +164,27 @@ export const migrateSuite = {
|
|
|
163
164
|
const cmdConfig = t.write(t.at('cmd-user', 'config.json'), JSON.stringify({ ...JSON.parse(JSON.stringify(old.defaults)), sandbox: { memoryMb: 4096 } }, null, 2));
|
|
164
165
|
const service = new MigrateService({ storageRoot: t.dir('cmd-storage'), userDir: cmdUser, configPath: cmdConfig }, '9.9.9', MIGRATIONS, () => false);
|
|
165
166
|
const noticed = service.versionChanged();
|
|
166
|
-
|
|
167
|
-
const
|
|
168
|
-
|
|
169
|
-
|
|
167
|
+
// sandbox migrate's work through the feature: the logged lines, then the line it returns.
|
|
168
|
+
const runM = async (input) => {
|
|
169
|
+
const { io, seen } = fakeIO(input.answers ?? []);
|
|
170
|
+
const restore = input.restore ? { restore: input.restore } : {};
|
|
171
|
+
const out = await migrateWith(service, { dryRun: input.dryRun, ...restore }, io);
|
|
172
|
+
return [...seen.logs.map((l) => l.text), out.line].join('\n');
|
|
173
|
+
};
|
|
174
|
+
const dry = await runM({ dryRun: true });
|
|
170
175
|
const untouched = readText(cmdConfig).includes('"toolchains"');
|
|
171
|
-
|
|
172
|
-
await
|
|
173
|
-
const ran = lines.join('\n');
|
|
174
|
-
lines.length = 0;
|
|
175
|
-
await runMigrate(service, { dryRun: true }, say);
|
|
176
|
+
const ran = await runM({ dryRun: false });
|
|
177
|
+
const again = await runM({ dryRun: true });
|
|
176
178
|
t.check(noticed &&
|
|
177
179
|
dry.includes('2026-10-unpin-config-defaults') &&
|
|
178
180
|
untouched &&
|
|
179
181
|
ran.includes('Updated: 2026-10-unpin-config-defaults.') &&
|
|
180
182
|
!service.versionChanged() &&
|
|
181
|
-
|
|
183
|
+
again === 'Nothing to update.', 'a dry run lists the pending change and changes nothing; a run applies it and moves the record on');
|
|
182
184
|
const backups = t.at('cmd-storage', 'backups');
|
|
183
185
|
const made = fs.readdirSync(backups);
|
|
184
186
|
fs.writeFileSync(cmdConfig, 'broken by hand');
|
|
185
|
-
await
|
|
187
|
+
await runM({ dryRun: false, restore: path.join(backups, made[0]), answers: [true] });
|
|
186
188
|
t.check(made.length === 1 && readText(cmdConfig).includes('"toolchains"'), 'the run kept one backup and --restore puts the saved files back');
|
|
187
189
|
t.check(!autoMigrates('self-test', false) &&
|
|
188
190
|
!autoMigrates('migrate', false) &&
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { isSandboxAddress } from '../host/channel/index.js';
|
|
2
|
-
import { buildFirewallCommands, cidrToRange, ipv4DnsServers, parseDefaultGateways, parseDnsServers, subtractIps, } from '../shared/network/index.js';
|
|
2
|
+
import { attachRuleCommands, hasShortName, buildFirewallCommands, cidrToRange, ipv4DnsServers, parseDefaultGateways, parseDnsServers, subtractIps, } from '../shared/network/index.js';
|
|
3
3
|
import { expandAllowList, hostAllowed, withBlockedHosts } from '../shared/network/index.js';
|
|
4
4
|
export const networkSuite = {
|
|
5
5
|
name: 'network',
|
|
@@ -11,6 +11,25 @@ export const networkSuite = {
|
|
|
11
11
|
const remaining = subtractIps([[start172, end172]], ['172.28.0.1']);
|
|
12
12
|
t.check(remaining.every(([start, end]) => gateway < start || gateway > end), 'the private block minus the gateway no longer contains the gateway');
|
|
13
13
|
t.excludes(buildFirewallCommands(['8.8.8.8']).join(), '8.8.8.8', 'public addresses are not part of the private-range rules');
|
|
14
|
+
t.section('the attach rule');
|
|
15
|
+
const exe = 'C:\\Users\\Me\\AppData\\Local\\Temp\\agent-sandbox\\ptyhost-abc.exe';
|
|
16
|
+
const attach = attachRuleCommands(exe);
|
|
17
|
+
t.equal(attach[0], ['advfirewall', 'firewall', 'delete', 'rule', 'name=AgentSandbox-Attach'], 'attach: the old rule is deleted first');
|
|
18
|
+
t.equal(attach[1].slice(2), [
|
|
19
|
+
'add',
|
|
20
|
+
'rule',
|
|
21
|
+
'name=AgentSandbox-Attach',
|
|
22
|
+
'dir=in',
|
|
23
|
+
'action=allow',
|
|
24
|
+
'enable=yes',
|
|
25
|
+
'profile=any',
|
|
26
|
+
'protocol=tcp',
|
|
27
|
+
'remoteip=LocalSubnet',
|
|
28
|
+
'program=' + exe,
|
|
29
|
+
], 'attach: inbound TCP to ptyhost only, from the local subnet only');
|
|
30
|
+
t.check(hasShortName('C:\\Users\\WDAGUT~1\\AppData\\Local\\Temp\\agent-sandbox\\ptyhost.exe'), 'an 8.3 short path is recognised (netsh cannot resolve it: "The application name could not be resolved")');
|
|
31
|
+
t.check(!hasShortName('C:\\Users\\WDAGUtilityAccount\\AppData\\Local\\Temp\\ptyhost.exe'), 'a long path is left alone');
|
|
32
|
+
t.check(!hasShortName('C:\\Users\\a~b\\x.exe'), 'a tilde not followed by a digit is not a short name');
|
|
14
33
|
t.section('reading Windows output');
|
|
15
34
|
t.equal(parseDefaultGateways(' 0.0.0.0 0.0.0.0 172.28.80.1 172.28.85.200 5\n'), ['172.28.80.1'], 'the default gateway is read from the route table');
|
|
16
35
|
t.equal(parseDnsServers(' DNS Servers . . . : 172.28.80.1\n 8.8.8.8\n NetBIOS : x\n'), ['172.28.80.1', '8.8.8.8'], 'DNS servers are read from ipconfig output');
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
// PowerShell variable hygiene: scripts/check-variables.ps1 reads every .ps1 of the repository with the PowerShell 5.1
|
|
2
|
+
// parser and reports automatic variables used as ordinary ones, names that differ from a parameter only in case,
|
|
3
|
+
// preference variables leaking out of functions, names a dot-sourced file shares with its caller, and reads before an
|
|
4
|
+
// assignment. It must find nothing in the repository, and it must still find each kind in a deliberately bad file.
|
|
5
|
+
import fs from 'node:fs';
|
|
6
|
+
import path from 'node:path';
|
|
7
|
+
import { spawnSync } from 'node:child_process';
|
|
8
|
+
import { isWin } from '../core/util/index.js';
|
|
9
|
+
import { SYSTEM } from '../shared/system.js';
|
|
10
|
+
const SKIP_FOLDERS = new Set(['node_modules', 'dist', '.git', '.claude']);
|
|
11
|
+
function powershellFiles(folder, found = []) {
|
|
12
|
+
for (const entry of fs.readdirSync(folder, { withFileTypes: true })) {
|
|
13
|
+
const full = path.join(folder, entry.name);
|
|
14
|
+
if (entry.isDirectory()) {
|
|
15
|
+
if (!SKIP_FOLDERS.has(entry.name))
|
|
16
|
+
powershellFiles(full, found);
|
|
17
|
+
}
|
|
18
|
+
else if (entry.name.endsWith('.ps1'))
|
|
19
|
+
found.push(full);
|
|
20
|
+
}
|
|
21
|
+
return found;
|
|
22
|
+
}
|
|
23
|
+
function check(checker, files) {
|
|
24
|
+
const run = spawnSync(SYSTEM.powershell(), ['-NoProfile', '-NonInteractive', '-ExecutionPolicy', 'Bypass', '-File', checker, ...files], { encoding: 'utf8', windowsHide: true, timeout: 180000 });
|
|
25
|
+
return { status: run.status, report: run.stderr.trim() };
|
|
26
|
+
}
|
|
27
|
+
const BAD_SCRIPT = [
|
|
28
|
+
'param([switch]$AutoUpdate)',
|
|
29
|
+
'$autoUpdate = 1',
|
|
30
|
+
'$matches = 3',
|
|
31
|
+
'foreach ($input in 1, 2) { }',
|
|
32
|
+
'function F { $global:ErrorActionPreference = "Stop"; $env:SOME_VARIABLE = 1; $x = $notSetAnywhere }',
|
|
33
|
+
'',
|
|
34
|
+
].join('\r\n');
|
|
35
|
+
export const powershellVariablesSuite = {
|
|
36
|
+
name: 'ps-variables',
|
|
37
|
+
title: 'PowerShell scripts: no automatic-variable, case or scope collisions',
|
|
38
|
+
run: (t) => {
|
|
39
|
+
const checker = path.join(t.packageRoot, 'scripts', 'check-variables.ps1');
|
|
40
|
+
if (!isWin || !fs.existsSync(checker)) {
|
|
41
|
+
t.skip('needs Windows PowerShell and scripts/check-variables.ps1');
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
t.section('the checker finds each kind of collision');
|
|
45
|
+
const bad = t.at('bad-variables.ps1');
|
|
46
|
+
fs.writeFileSync(bad, BAD_SCRIPT);
|
|
47
|
+
const caught = check(checker, [bad]);
|
|
48
|
+
t.equal(caught.status, 1, 'a bad script fails the check');
|
|
49
|
+
for (const kind of ['automatic', 'case', 'preference', 'env', 'unassigned', 'script-scope']) {
|
|
50
|
+
t.check(caught.report.includes(': ' + kind + ':'), 'it reports "' + kind + '"');
|
|
51
|
+
}
|
|
52
|
+
t.section('the repository scripts are clean');
|
|
53
|
+
const files = ['native', 'sandbox', 'scripts']
|
|
54
|
+
.map((folder) => path.join(t.packageRoot, folder))
|
|
55
|
+
.filter((folder) => fs.existsSync(folder))
|
|
56
|
+
.flatMap((folder) => powershellFiles(folder));
|
|
57
|
+
t.check(files.length > 0, 'it found the scripts (' + files.length + ')');
|
|
58
|
+
const clean = check(checker, files);
|
|
59
|
+
t.equal(clean.status, 0, 'no collisions' + (clean.report ? ':\n' + clean.report : ''));
|
|
60
|
+
},
|
|
61
|
+
};
|
|
@@ -59,6 +59,7 @@ export const LAUNCH_FILES_GOLDEN = [
|
|
|
59
59
|
'sandbox/scripts/install-shell-path.ps1',
|
|
60
60
|
'sandbox/scripts/link-profile-dirs.ps1',
|
|
61
61
|
'sandbox/scripts/new-shortcuts.ps1',
|
|
62
|
+
'sandbox/scripts/repair-wmi-services.ps1',
|
|
62
63
|
'sandbox/scripts/set-desktop.ps1',
|
|
63
64
|
'sandbox/scripts/set-dns-servers.ps1',
|
|
64
65
|
'sandbox/scripts/set-machine-environment.ps1',
|
|
@@ -103,6 +103,9 @@ export declare function createFixtures(t: Harness): {
|
|
|
103
103
|
configFile: string;
|
|
104
104
|
killSwitch: boolean;
|
|
105
105
|
};
|
|
106
|
+
github: {
|
|
107
|
+
shareToken: boolean;
|
|
108
|
+
};
|
|
106
109
|
provisioning: {
|
|
107
110
|
copyFromHost: boolean;
|
|
108
111
|
fallbackToInstall: boolean;
|
|
@@ -253,10 +256,12 @@ export declare function createFixtures(t: Harness): {
|
|
|
253
256
|
reuseSession: boolean;
|
|
254
257
|
auto: boolean;
|
|
255
258
|
autoHide: boolean;
|
|
259
|
+
confirmCtrlC: boolean;
|
|
256
260
|
};
|
|
257
261
|
web: {
|
|
258
262
|
enabled: boolean;
|
|
259
263
|
port: number;
|
|
264
|
+
openOnLaunch: boolean;
|
|
260
265
|
};
|
|
261
266
|
agentCommands: {
|
|
262
267
|
enabled: boolean;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|