windows-development-sandbox 1.7.0 → 1.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/config.example.json +12 -1
- package/dist/app/context.d.ts +8 -0
- package/dist/app/context.js +12 -0
- package/dist/app/features/defs.d.ts +322 -0
- package/dist/app/features/defs.js +28 -0
- package/dist/app/features/sandbox/index.d.ts +2 -0
- package/dist/app/features/sandbox/index.js +3 -0
- package/dist/app/features/sandbox/sandbox.def.d.ts +193 -0
- package/dist/app/features/sandbox/sandbox.def.js +245 -0
- package/dist/app/features/sandbox/sandbox.run.d.ts +72 -0
- package/dist/app/features/sandbox/sandbox.run.js +98 -0
- package/dist/app/features/sessions/index.d.ts +2 -0
- package/dist/app/features/sessions/index.js +3 -0
- package/dist/app/features/sessions/sessions.def.d.ts +141 -0
- package/dist/app/features/sessions/sessions.def.js +176 -0
- package/dist/app/features/sessions/sessions.run.d.ts +39 -0
- package/dist/app/features/sessions/sessions.run.js +58 -0
- package/dist/{cli/menu/settings/categories.d.ts → app/features/settings/categories.def.d.ts} +2 -0
- package/dist/{cli/menu/settings/categories.js → app/features/settings/categories.def.js} +24 -5
- package/dist/app/features/settings/index.d.ts +5 -0
- package/dist/app/features/settings/index.js +6 -0
- package/dist/{cli/menu/settings/config-file.d.ts → app/features/settings/settings-file.d.ts} +1 -1
- package/dist/{cli/menu/settings/config-file.js → app/features/settings/settings-file.js} +1 -1
- package/dist/app/features/settings/settings-rows.d.ts +35 -0
- package/dist/app/features/settings/settings-rows.js +94 -0
- package/dist/app/features/settings/settings.def.d.ts +157 -0
- package/dist/app/features/settings/settings.def.js +179 -0
- package/dist/app/features/settings/settings.run.d.ts +67 -0
- package/dist/app/features/settings/settings.run.js +84 -0
- package/dist/app/kernel/define.d.ts +143 -0
- package/dist/app/kernel/define.js +42 -0
- package/dist/app/kernel/errors.d.ts +34 -0
- package/dist/app/kernel/errors.js +45 -0
- package/dist/app/kernel/fields.d.ts +70 -0
- package/dist/app/kernel/fields.js +243 -0
- package/dist/app/kernel/index.d.ts +8 -0
- package/dist/app/kernel/index.js +10 -0
- package/dist/app/kernel/io.d.ts +193 -0
- package/dist/app/kernel/io.js +126 -0
- package/dist/app/kernel/rpc.d.ts +156 -0
- package/dist/app/kernel/rpc.js +47 -0
- package/dist/app/kernel/text.d.ts +6 -0
- package/dist/app/kernel/text.js +57 -0
- package/dist/app/kernel/view.d.ts +146 -0
- package/dist/app/kernel/view.js +28 -0
- package/dist/app/registry.d.ts +10 -0
- package/dist/app/registry.js +50 -0
- package/dist/cli/args.d.ts +5 -0
- package/dist/cli/args.js +6 -0
- package/dist/cli/commands/engine.d.ts +2 -0
- package/dist/cli/commands/engine.js +60 -0
- package/dist/cli/commands/index.d.ts +1 -1
- package/dist/cli/commands/index.js +1 -1
- package/dist/cli/commands/launch/launch.js +49 -7
- package/dist/cli/commands/launch/prepare.js +3 -3
- package/dist/cli/commands/launch/running.js +2 -1
- package/dist/cli/commands/launch/summary.d.ts +2 -0
- package/dist/cli/commands/maintenance/config-share.d.ts +12 -0
- package/dist/cli/commands/maintenance/config-share.js +80 -0
- package/dist/cli/commands/maintenance/config.js +8 -82
- package/dist/cli/commands/maintenance/logs.js +14 -0
- package/dist/cli/commands/registry.js +3 -7
- package/dist/cli/commands/repair/checks/contained.d.ts +2 -0
- package/dist/cli/commands/repair/checks/contained.js +139 -0
- package/dist/cli/commands/repair/checks/hcs.d.ts +7 -0
- package/dist/cli/commands/repair/checks/hcs.js +28 -0
- package/dist/cli/commands/repair/checks/index.js +4 -0
- package/dist/cli/commands/repair/checks/pc.js +32 -1
- package/dist/cli/commands/repair/checks/sandbox.js +16 -1
- package/dist/cli/commands/repair/checks/vpn.js +34 -9
- package/dist/cli/commands/repair/env.js +2 -1
- package/dist/cli/commands/sessions/index.d.ts +0 -4
- package/dist/cli/commands/sessions/index.js +3 -7
- package/dist/cli/commands/shared-use.d.ts +5 -2
- package/dist/cli/commands/shared-use.js +11 -8
- package/dist/cli/commands/storage/contained.d.ts +3 -0
- package/dist/cli/commands/storage/contained.js +179 -0
- package/dist/cli/commands/storage/offer.js +7 -1
- package/dist/cli/commands/storage/storage.js +10 -2
- package/dist/cli/commands/user-config.js +1 -1
- package/dist/cli/commands/vpn.js +20 -3
- package/dist/cli/commands/web.d.ts +5 -0
- package/dist/cli/commands/web.js +40 -0
- package/dist/cli/index.js +2 -1
- package/dist/cli/manifest.d.ts +72 -104
- package/dist/cli/manifest.js +64 -39
- package/dist/cli/menu/add-agent.d.ts +1 -1
- package/dist/cli/menu/add-agent.js +1 -1
- package/dist/cli/menu/apps.d.ts +7 -1
- package/dist/cli/menu/apps.js +36 -0
- package/dist/cli/menu/command-fields.d.ts +1 -1
- package/dist/cli/menu/command-form.js +2 -2
- package/dist/cli/menu/io-menu.d.ts +29 -0
- package/dist/cli/menu/io-menu.js +126 -0
- package/dist/cli/menu/live.d.ts +27 -0
- package/dist/cli/menu/live.js +69 -0
- package/dist/cli/menu/memory.d.ts +19 -0
- package/dist/cli/menu/memory.js +53 -0
- package/dist/cli/menu/menu.d.ts +10 -1
- package/dist/cli/menu/menu.js +27 -9
- package/dist/cli/menu/pages/agents-page.d.ts +3 -1
- package/dist/cli/menu/pages/agents-page.js +12 -5
- package/dist/cli/menu/pages/apps-page.d.ts +3 -1
- package/dist/cli/menu/pages/apps-page.js +19 -2
- package/dist/cli/menu/pages/list-page.d.ts +27 -0
- package/dist/cli/menu/pages/list-page.js +109 -7
- package/dist/cli/menu/pages/maintenance-page.d.ts +0 -5
- package/dist/cli/menu/pages/maintenance-page.js +17 -19
- package/dist/cli/menu/pages/sandbox-page.d.ts +4 -6
- package/dist/cli/menu/pages/sandbox-page.js +26 -118
- package/dist/cli/menu/pages/scopes.d.ts +1 -1
- package/dist/cli/menu/pages/sessions-page.d.ts +5 -11
- package/dist/cli/menu/pages/sessions-page.js +19 -88
- package/dist/cli/menu/pages/settings-page.d.ts +2 -10
- package/dist/cli/menu/pages/settings-page.js +64 -94
- package/dist/cli/menu/render-view.d.ts +28 -0
- package/dist/cli/menu/render-view.js +112 -0
- package/dist/cli/menu/settings/{path-kind.d.ts → ask-path.d.ts} +1 -7
- package/dist/cli/menu/settings/ask-path.js +14 -0
- package/dist/cli/menu/settings/collections/collection-editor.d.ts +1 -1
- package/dist/cli/menu/settings/collections/string-list-editor.d.ts +1 -2
- package/dist/cli/menu/settings/collections/string-list-editor.js +1 -1
- package/dist/cli/menu/settings/draft.d.ts +1 -1
- package/dist/cli/menu/settings/format.d.ts +1 -3
- package/dist/cli/menu/settings/format.js +6 -36
- package/dist/cli/menu/settings/index.d.ts +1 -3
- package/dist/cli/menu/settings/index.js +3 -3
- package/dist/cli/menu/settings/object-editor.d.ts +1 -1
- package/dist/cli/menu/settings/share.d.ts +36 -0
- package/dist/cli/menu/settings/share.js +131 -0
- package/dist/cli/menu/settings/value-editor.d.ts +5 -1
- package/dist/cli/menu/settings/value-editor.js +57 -54
- package/dist/cli/menu/several.js +1 -1
- package/dist/cli/menu/share-settings.d.ts +21 -0
- package/dist/cli/menu/share-settings.js +112 -0
- package/dist/cli/menu/shell.d.ts +21 -5
- package/dist/cli/menu/shell.js +31 -6
- package/dist/cli/menu/views.d.ts +7 -0
- package/dist/cli/menu/views.js +11 -0
- package/dist/cli/menu/vpn-login.js +8 -0
- package/dist/cli/operations/handler.d.ts +6 -0
- package/dist/cli/operations/handler.js +61 -0
- package/dist/cli/operations/index.d.ts +4 -0
- package/dist/cli/operations/index.js +5 -0
- package/dist/cli/operations/input.d.ts +6 -0
- package/dist/cli/operations/input.js +37 -0
- package/dist/cli/operations/io-cli.d.ts +7 -0
- package/dist/cli/operations/io-cli.js +62 -0
- package/dist/cli/operations/spec.d.ts +18 -0
- package/dist/cli/operations/spec.js +108 -0
- package/dist/cli/output/colors.d.ts +2 -2
- package/dist/cli/output/colors.js +2 -11
- package/dist/cli/output/index.d.ts +1 -0
- package/dist/cli/output/index.js +1 -0
- package/dist/cli/output/print.d.ts +3 -1
- package/dist/cli/output/print.js +7 -3
- package/dist/cli/output/progress.d.ts +15 -0
- package/dist/cli/output/progress.js +44 -0
- package/dist/cli/output/render-view.d.ts +4 -0
- package/dist/cli/output/render-view.js +63 -0
- package/dist/cli/services/agent-commands-service.d.ts +2 -0
- package/dist/cli/services/agent-commands-service.js +11 -2
- package/dist/cli/services/logs-service.js +4 -3
- package/dist/cli/tui/app.d.ts +6 -1
- package/dist/cli/tui/app.js +26 -4
- package/dist/cli/tui/list/list-screen.d.ts +14 -0
- package/dist/cli/tui/list/list-screen.js +64 -36
- package/dist/cli/tui/list/list-types.d.ts +2 -0
- package/dist/cli/tui/terminal.d.ts +7 -0
- package/dist/cli/tui/terminal.js +30 -10
- package/dist/core/config/defaults.js +9 -1
- package/dist/core/schema/config.d.ts +14 -0
- package/dist/core/schema/config.js +16 -1
- package/dist/core/schema/harness.d.ts +1 -0
- package/dist/core/schema/harness.js +5 -0
- package/dist/core/schema/sandbox.d.ts +6 -0
- package/dist/core/schema/sandbox.js +20 -3
- package/dist/core/schema/vpn.d.ts +2 -1
- package/dist/core/schema/vpn.js +4 -4
- package/dist/core/schema/web.d.ts +1 -0
- package/dist/core/schema/web.js +4 -1
- package/dist/core/types.d.ts +23 -5
- package/dist/core/util/fs.d.ts +2 -0
- package/dist/core/util/fs.js +9 -0
- package/dist/core/util/index.d.ts +1 -1
- package/dist/core/util/index.js +1 -1
- package/dist/guest/agents/agent-files.d.ts +5 -0
- package/dist/guest/agents/agent-files.js +4 -0
- package/dist/guest/agents/local-state.d.ts +2 -0
- package/dist/guest/agents/local-state.js +21 -1
- package/dist/guest/boot/boot.js +5 -2
- package/dist/guest/daemon/daemon.js +4 -0
- package/dist/guest/daemon/sessions.d.ts +5 -0
- package/dist/guest/daemon/sessions.js +17 -3
- package/dist/guest/entries/daemon.js +3 -0
- package/dist/guest/governor/decide.d.ts +71 -0
- package/dist/guest/governor/decide.js +211 -0
- package/dist/guest/governor/governor.d.ts +45 -0
- package/dist/guest/governor/governor.js +230 -0
- package/dist/guest/governor/index.d.ts +2 -0
- package/dist/guest/governor/index.js +2 -0
- package/dist/guest/network/firewall.d.ts +1 -0
- package/dist/guest/network/firewall.js +65 -23
- package/dist/guest/runtime/csc.d.ts +1 -0
- package/dist/guest/runtime/csc.js +1 -0
- package/dist/guest/runtime/process.js +53 -5
- package/dist/guest/sessions/viewer.js +3 -1
- package/dist/guest/setup/claude-mem.js +12 -4
- package/dist/guest/toolchains/languages/node.js +29 -3
- package/dist/guest/toolchains/native/rust-extras.js +4 -2
- package/dist/guest/vpn/vpn.js +69 -21
- package/dist/guest/vpn/wireguard.d.ts +32 -0
- package/dist/guest/vpn/wireguard.js +132 -0
- package/dist/host/agent-commands/commands.d.ts +4 -0
- package/dist/host/agent-commands/commands.js +31 -7
- package/dist/host/audit/log.d.ts +1 -1
- package/dist/host/channel/attach.d.ts +3 -1
- package/dist/host/channel/attach.js +5 -2
- package/dist/host/channel/channel.d.ts +2 -0
- package/dist/host/channel/channel.js +4 -0
- package/dist/host/engines/engine.d.ts +12 -0
- package/dist/host/engines/engine.js +1 -0
- package/dist/host/engines/hcs/check.d.ts +25 -0
- package/dist/host/engines/hcs/check.js +95 -0
- package/dist/host/engines/hcs/documents.d.ts +44 -0
- package/dist/host/engines/hcs/documents.js +155 -0
- package/dist/host/engines/hcs/engine.d.ts +39 -0
- package/dist/host/engines/hcs/engine.js +171 -0
- package/dist/host/engines/hcs/helper.d.ts +43 -0
- package/dist/host/engines/hcs/helper.js +173 -0
- package/dist/host/engines/hcs/images.d.ts +37 -0
- package/dist/host/engines/hcs/images.js +152 -0
- package/dist/host/engines/index.d.ts +7 -0
- package/dist/host/engines/index.js +5 -0
- package/dist/host/engines/registry.d.ts +16 -0
- package/dist/host/engines/registry.js +30 -0
- package/dist/host/engines/types.d.ts +58 -0
- package/dist/host/engines/types.js +1 -0
- package/dist/host/engines/windows-sandbox/engine.d.ts +16 -0
- package/dist/host/engines/windows-sandbox/engine.js +63 -0
- package/dist/host/engines/windows-sandbox/wsb-text.d.ts +2 -0
- package/dist/host/engines/windows-sandbox/wsb-text.js +29 -0
- package/dist/host/launch/generate.d.ts +5 -1
- package/dist/host/launch/generate.js +50 -8
- package/dist/host/launch/index.d.ts +3 -1
- package/dist/host/launch/index.js +3 -1
- package/dist/host/launch/launch-plan.d.ts +13 -0
- package/dist/host/launch/launch-plan.js +26 -0
- package/dist/host/launch/mappings.js +2 -1
- package/dist/host/launch/risk-notes.d.ts +10 -0
- package/dist/host/launch/risk-notes.js +18 -0
- package/dist/host/launch/session-file.d.ts +2 -0
- package/dist/host/launch/session-file.js +7 -1
- package/dist/host/launch/wsb-file.d.ts +28 -4
- package/dist/host/launch/wsb-file.js +61 -42
- package/dist/host/life/crash-report.d.ts +27 -1
- package/dist/host/life/crash-report.js +173 -7
- package/dist/host/life/host-memory.d.ts +41 -0
- package/dist/host/life/host-memory.js +140 -0
- package/dist/host/life/index.d.ts +2 -0
- package/dist/host/life/index.js +2 -0
- package/dist/host/life/stop-events.d.ts +2 -0
- package/dist/host/life/stop-events.js +20 -3
- package/dist/host/life/stop-warning.js +1 -1
- package/dist/host/life/watchdog.d.ts +56 -0
- package/dist/host/life/watchdog.js +124 -0
- package/dist/host/native.d.ts +3 -2
- package/dist/host/native.js +22 -3
- package/dist/host/profile/claude-login.js +3 -2
- package/dist/host/sandbox/contained-deps.d.ts +2 -0
- package/dist/host/sandbox/contained-deps.js +17 -0
- package/dist/host/sandbox/index.d.ts +2 -0
- package/dist/host/sandbox/index.js +2 -0
- package/dist/host/sandbox/platform.d.ts +2 -0
- package/dist/host/sandbox/platform.js +7 -7
- package/dist/host/sandbox/tasklist.d.ts +13 -0
- package/dist/host/sandbox/tasklist.js +47 -0
- package/dist/host/secrets/launch-secrets.js +2 -1
- package/dist/host/sharing/current.js +2 -6
- package/dist/host/storage/contained/check.d.ts +9 -0
- package/dist/host/storage/contained/check.js +37 -0
- package/dist/host/storage/contained/contained-storage.d.ts +66 -0
- package/dist/host/storage/contained/contained-storage.js +168 -0
- package/dist/host/storage/contained/disk-port.d.ts +43 -0
- package/dist/host/storage/contained/disk-port.js +122 -0
- package/dist/host/storage/contained/index.d.ts +9 -0
- package/dist/host/storage/contained/index.js +8 -0
- package/dist/host/storage/contained/layout.d.ts +28 -0
- package/dist/host/storage/contained/layout.js +45 -0
- package/dist/host/storage/contained/resolve.d.ts +4 -0
- package/dist/host/storage/contained/resolve.js +30 -0
- package/dist/host/storage/contained/setting.d.ts +1 -0
- package/dist/host/storage/contained/setting.js +5 -0
- package/dist/host/storage/contained/state.d.ts +89 -0
- package/dist/host/storage/contained/state.js +166 -0
- package/dist/host/storage/contained/transfer.d.ts +24 -0
- package/dist/host/storage/contained/transfer.js +121 -0
- package/dist/host/storage/index.d.ts +2 -0
- package/dist/host/storage/index.js +2 -0
- package/dist/host/storage/providers/contained.d.ts +15 -0
- package/dist/host/storage/providers/contained.js +39 -0
- package/dist/host/storage/providers/folder.d.ts +12 -0
- package/dist/host/storage/providers/folder.js +20 -0
- package/dist/host/storage/providers/index.d.ts +4 -0
- package/dist/host/storage/providers/index.js +3 -0
- package/dist/host/storage/providers/registry.d.ts +9 -0
- package/dist/host/storage/providers/registry.js +14 -0
- package/dist/host/storage/providers/types.d.ts +33 -0
- package/dist/host/storage/providers/types.js +1 -0
- package/dist/host/tools/conpty.js +3 -2
- package/dist/host/tools/windows-terminal.js +8 -7
- package/dist/host/vpn/index.d.ts +1 -1
- package/dist/host/vpn/index.js +1 -1
- package/dist/host/vpn/prepare.d.ts +2 -0
- package/dist/host/vpn/prepare.js +63 -2
- package/dist/host/web/browser.d.ts +2 -0
- package/dist/host/web/browser.js +14 -1
- package/dist/host/web/index.d.ts +3 -2
- package/dist/host/web/index.js +3 -2
- package/dist/host/web/rpc.d.ts +24 -0
- package/dist/host/web/rpc.js +149 -0
- package/dist/host/web/runner.d.ts +2 -0
- package/dist/host/web/runner.js +1 -2
- package/dist/host/web/server.d.ts +7 -0
- package/dist/host/web/server.js +23 -3
- package/dist/runtime/agent.js +83 -18
- package/dist/runtime/daemon.js +1805 -1221
- package/dist/runtime/db.js +83 -18
- package/dist/runtime/main.js +779 -219
- package/dist/runtime/netproxy.js +73 -11
- package/dist/runtime/view.js +91 -16
- package/dist/selftest/agent-paths.test.js +11 -1
- package/dist/selftest/app.test.d.ts +2 -0
- package/dist/selftest/app.test.js +324 -0
- package/dist/selftest/channel.test.js +13 -0
- package/dist/selftest/cli.test.js +2 -1
- package/dist/selftest/config.test.js +59 -0
- package/dist/selftest/contained.test.d.ts +2 -0
- package/dist/selftest/contained.test.js +544 -0
- package/dist/selftest/credentials.test.js +1 -1
- package/dist/selftest/engine.test.d.ts +2 -0
- package/dist/selftest/engine.test.js +127 -0
- package/dist/selftest/guest-boot.test.js +47 -1
- package/dist/selftest/hcs.test.d.ts +2 -0
- package/dist/selftest/hcs.test.js +482 -0
- package/dist/selftest/heavy-load.test.d.ts +2 -0
- package/dist/selftest/heavy-load.test.js +355 -0
- package/dist/selftest/index.js +12 -0
- package/dist/selftest/layout.test.js +12 -0
- package/dist/selftest/menu-perf.test.d.ts +2 -0
- package/dist/selftest/menu-perf.test.js +248 -0
- package/dist/selftest/menu-screens.js +4 -2
- package/dist/selftest/menu.test.js +36 -8
- package/dist/selftest/network.test.js +20 -1
- package/dist/selftest/support/engine-cases.d.ts +8 -0
- package/dist/selftest/support/engine-cases.js +65 -0
- package/dist/selftest/support/engine-golden.d.ts +3 -0
- package/dist/selftest/support/engine-golden.js +66 -0
- package/dist/selftest/support/fixtures.d.ts +8 -1
- package/dist/selftest/support/hcs-probes.d.ts +17 -0
- package/dist/selftest/support/hcs-probes.js +41 -0
- package/dist/selftest/vpn.test.js +136 -3
- package/dist/selftest/web.test.js +101 -3
- package/dist/shared/channel/run-dir.d.ts +4 -1
- package/dist/shared/channel/run-dir.js +7 -1
- package/dist/shared/channel/schema.d.ts +35 -1
- package/dist/shared/channel/schema.js +27 -0
- package/dist/shared/channel/secrets.d.ts +1 -0
- package/dist/shared/channel/secrets.js +6 -0
- package/dist/shared/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/index.d.ts +1 -0
- package/dist/shared/memory/index.js +1 -0
- package/dist/shared/memory/policy.d.ts +38 -0
- package/dist/shared/memory/policy.js +63 -0
- package/dist/shared/network/firewall-rules.d.ts +8 -0
- package/dist/shared/network/firewall-rules.js +28 -0
- package/dist/shared/pty/output-filter.d.ts +14 -1
- package/dist/shared/pty/output-filter.js +22 -4
- package/dist/shared/pty/terminal.d.ts +4 -1
- package/dist/shared/pty/terminal.js +4 -2
- package/dist/shared/system.d.ts +1 -0
- package/dist/shared/system.js +1 -0
- package/dist/shared/vpn/download.d.ts +16 -0
- package/dist/shared/vpn/download.js +16 -0
- package/dist/shared/vpn/wireguard.d.ts +51 -0
- package/dist/shared/vpn/wireguard.js +227 -0
- package/dist/sync/sync-cycle.js +5 -5
- package/dist/sync/watcher.d.ts +13 -0
- package/dist/sync/watcher.js +92 -3
- package/dist/web/index.html +4 -3
- package/dist/web/main-NRRS5O6Z.js +157 -0
- package/dist/web/main-T5DMCHYV.css +1 -0
- package/native/csharp/HcsHost/AssemblyInfo.cs +14 -0
- package/native/csharp/HcsHost/Guard.cs +100 -0
- package/native/csharp/HcsHost/Hcs.cs +256 -0
- package/native/csharp/HcsHost/Json.cs +78 -0
- package/native/csharp/HcsHost/Program.cs +185 -0
- package/native/csharp/HcsHost/VirtualDisk.cs +95 -0
- package/native/csharp/HostTools/AssemblyInfo.cs +14 -0
- package/native/csharp/HostTools/MemoryStatus.cs +128 -0
- package/native/csharp/HostTools/Program.cs +58 -17
- package/native/scripts/check-contained.ps1 +28 -0
- package/native/scripts/contained-common.ps1 +241 -0
- package/native/scripts/dismount-contained.ps1 +66 -0
- package/native/scripts/memory-status.ps1 +42 -0
- package/native/scripts/mount-contained.ps1 +139 -0
- package/native/scripts/run-elevated.ps1 +17 -4
- package/native/scripts/stop-events.ps1 +23 -8
- package/package.json +9 -2
- package/sandbox/csharp/MemGov.cs +466 -0
- package/sandbox/csharp/PtyHost.cs +111 -5
- package/sandbox/scripts/new-shortcuts.ps1 +3 -1
- package/schemas/config.schema.json +66 -8
- package/schemas/sandbox-config.schema.json +3 -3
- package/dist/cli/commands/sessions/control.d.ts +0 -4
- package/dist/cli/commands/sessions/control.js +0 -66
- package/dist/cli/commands/sessions/list.d.ts +0 -2
- package/dist/cli/commands/sessions/list.js +0 -48
- package/dist/cli/commands/sessions/status.d.ts +0 -4
- package/dist/cli/commands/sessions/status.js +0 -114
- package/dist/cli/commands/sessions/window.d.ts +0 -3
- package/dist/cli/commands/sessions/window.js +0 -18
- package/dist/cli/menu/settings/path-kind.js +0 -44
- package/dist/web/main-CXESL347.js +0 -45
- package/dist/web/main-VLR7DVQ4.css +0 -1
- /package/dist/{cli/menu/settings → app/kernel}/schema-node.d.ts +0 -0
- /package/dist/{cli/menu/settings → app/kernel}/schema-node.js +0 -0
package/dist/cli/tui/app.d.ts
CHANGED
|
@@ -9,16 +9,21 @@ import { Terminal } from './terminal.js';
|
|
|
9
9
|
import type { Screen } from './screen.js';
|
|
10
10
|
export declare class App {
|
|
11
11
|
readonly terminal: Terminal;
|
|
12
|
-
/** The status line for screens that do not set their own (
|
|
12
|
+
/** The status line for screens that do not set their own (read on every draw: it must not wait for anything). */
|
|
13
13
|
status: () => string;
|
|
14
|
+
/** Awaited after an action changed something, before the screen loads what it shows again. */
|
|
15
|
+
afterAction: () => Promise<void>;
|
|
14
16
|
/** The navigation on the left of every screen (none: no navigation column). */
|
|
15
17
|
nav: () => NavState | undefined;
|
|
16
18
|
/** The screens being shown, innermost last: a dialog is drawn over the one below it. */
|
|
17
19
|
private readonly shown;
|
|
18
20
|
private redrawNow;
|
|
21
|
+
private redrawTimer;
|
|
19
22
|
constructor(terminal?: Terminal);
|
|
20
23
|
/** Draws the screen on top again now (before a slow piece of work, so its notice is visible). */
|
|
21
24
|
redraw(): void;
|
|
25
|
+
/** Draws it again soon: what happens between two keys (a resize, fresh facts) is drawn once, not once each. */
|
|
26
|
+
requestRedraw(): void;
|
|
22
27
|
/** Shows `screen` until its handler says it is done, and returns what it returned. */
|
|
23
28
|
show<T>(screen: Screen<T>): Promise<T>;
|
|
24
29
|
/** A dialog over the screen below (Save / Discard / Cancel, Yes / No ...). */
|
package/dist/cli/tui/app.js
CHANGED
|
@@ -9,22 +9,40 @@ import { Frame } from './frame.js';
|
|
|
9
9
|
import { ListScreen } from './list/list-screen.js';
|
|
10
10
|
import { Terminal } from './terminal.js';
|
|
11
11
|
import { Theme } from './theme.js';
|
|
12
|
+
/** Changes that arrive together (a resize, fresh facts) are drawn once, this long after the first. */
|
|
13
|
+
const REDRAW_DELAY_MS = 16;
|
|
14
|
+
/** While keys are waiting, the screen is still drawn at least this often. */
|
|
15
|
+
const MAX_STALE_MS = 100;
|
|
12
16
|
export class App {
|
|
13
17
|
terminal;
|
|
14
|
-
/** The status line for screens that do not set their own (
|
|
18
|
+
/** The status line for screens that do not set their own (read on every draw: it must not wait for anything). */
|
|
15
19
|
status = () => '';
|
|
20
|
+
/** Awaited after an action changed something, before the screen loads what it shows again. */
|
|
21
|
+
afterAction = () => Promise.resolve();
|
|
16
22
|
/** The navigation on the left of every screen (none: no navigation column). */
|
|
17
23
|
nav = () => undefined;
|
|
18
24
|
/** The screens being shown, innermost last: a dialog is drawn over the one below it. */
|
|
19
25
|
shown = [];
|
|
20
26
|
redrawNow = null;
|
|
27
|
+
redrawTimer;
|
|
21
28
|
constructor(terminal = new Terminal()) {
|
|
22
29
|
this.terminal = terminal;
|
|
30
|
+
terminal.onResized(() => this.requestRedraw());
|
|
23
31
|
}
|
|
24
32
|
/** Draws the screen on top again now (before a slow piece of work, so its notice is visible). */
|
|
25
33
|
redraw() {
|
|
26
34
|
this.redrawNow?.();
|
|
27
35
|
}
|
|
36
|
+
/** Draws it again soon: what happens between two keys (a resize, fresh facts) is drawn once, not once each. */
|
|
37
|
+
requestRedraw() {
|
|
38
|
+
if (this.redrawTimer)
|
|
39
|
+
return;
|
|
40
|
+
this.redrawTimer = setTimeout(() => {
|
|
41
|
+
this.redrawTimer = undefined;
|
|
42
|
+
if (this.terminal.running)
|
|
43
|
+
this.redrawNow?.();
|
|
44
|
+
}, REDRAW_DELAY_MS);
|
|
45
|
+
}
|
|
28
46
|
/** Shows `screen` until its handler says it is done, and returns what it returned. */
|
|
29
47
|
async show(screen) {
|
|
30
48
|
this.terminal.start();
|
|
@@ -39,10 +57,15 @@ export class App {
|
|
|
39
57
|
this.terminal.render(Frame.render({ ...parts, status: parts.status ?? this.status(), nav: nav && { ...nav, dimmed: nav.dimmed || covered } }, width, height));
|
|
40
58
|
};
|
|
41
59
|
this.redrawNow = draw;
|
|
42
|
-
|
|
60
|
+
let drawnAt = 0;
|
|
43
61
|
try {
|
|
44
62
|
for (;;) {
|
|
45
|
-
|
|
63
|
+
// Keys that are already waiting (a held arrow, a paste) are handled first: the screen shows the result of the
|
|
64
|
+
// last one, but never stays stale for longer than MAX_STALE_MS.
|
|
65
|
+
if (!this.terminal.hasKeys || Date.now() - drawnAt >= MAX_STALE_MS) {
|
|
66
|
+
draw();
|
|
67
|
+
drawnAt = Date.now();
|
|
68
|
+
}
|
|
46
69
|
const step = await screen.handle(await this.terminal.key());
|
|
47
70
|
if (step)
|
|
48
71
|
return step.done;
|
|
@@ -51,7 +74,6 @@ export class App {
|
|
|
51
74
|
finally {
|
|
52
75
|
this.shown.pop();
|
|
53
76
|
this.redrawNow = outer;
|
|
54
|
-
this.terminal.onResized(outer);
|
|
55
77
|
}
|
|
56
78
|
}
|
|
57
79
|
/** A dialog over the screen below (Save / Discard / Cancel, Yes / No ...). */
|
|
@@ -14,11 +14,21 @@ export declare class ListScreen<T> implements Screen<ListResult<T>> {
|
|
|
14
14
|
private searching;
|
|
15
15
|
private notice;
|
|
16
16
|
private readonly checked;
|
|
17
|
+
/** The entries shown for the last query and category (the items never change, so only those two matter). */
|
|
18
|
+
private shown;
|
|
19
|
+
/** What a search looks in, per entry, lowercased once. */
|
|
20
|
+
private haystacks;
|
|
17
21
|
constructor(o: ListOptions<T>);
|
|
18
22
|
/** Indexes of the entries shown now: all matches of the search, else the current category's, else all. */
|
|
19
23
|
private visible;
|
|
24
|
+
private matching;
|
|
25
|
+
private categoryLabel;
|
|
20
26
|
private rows;
|
|
21
27
|
render(size: Size): FrameParts;
|
|
28
|
+
/** The rows above the list: the tabs, the intro, the search box (with a blank row after them). */
|
|
29
|
+
private topLines;
|
|
30
|
+
/** The rows of the list that fit: scrolled to keep the cursor in view, with "▲ above / ▼ more" under them. */
|
|
31
|
+
private listLines;
|
|
22
32
|
private rowLine;
|
|
23
33
|
private sideLines;
|
|
24
34
|
private detailsLines;
|
|
@@ -40,6 +50,10 @@ export declare class ListScreen<T> implements Screen<ListResult<T>> {
|
|
|
40
50
|
get currentCategory(): string | undefined;
|
|
41
51
|
/** The extra keys that work now (they may depend on the category and on the highlighted entry). */
|
|
42
52
|
private actionsNow;
|
|
53
|
+
/** The value under the cursor (undefined: the list is empty). */
|
|
54
|
+
get current(): T | undefined;
|
|
55
|
+
/** The text of the search (empty: none). */
|
|
56
|
+
get searchText(): string;
|
|
43
57
|
/** Keys are going into the search box (digits and letters are text, not shortcuts). */
|
|
44
58
|
get isSearching(): boolean;
|
|
45
59
|
/** The entries ticked now (multi-select). */
|
|
@@ -14,9 +14,14 @@ export class ListScreen {
|
|
|
14
14
|
searching = false;
|
|
15
15
|
notice;
|
|
16
16
|
checked;
|
|
17
|
+
/** The entries shown for the last query and category (the items never change, so only those two matter). */
|
|
18
|
+
shown;
|
|
19
|
+
/** What a search looks in, per entry, lowercased once. */
|
|
20
|
+
haystacks;
|
|
17
21
|
constructor(o) {
|
|
18
22
|
this.o = o;
|
|
19
23
|
this.notice = o.notice;
|
|
24
|
+
this.query = o.startQuery ?? '';
|
|
20
25
|
this.checked = new Set(o.items.flatMap((item, i) => (item.checked ? [i] : [])));
|
|
21
26
|
const start = o.startAt === undefined ? -1 : o.items.findIndex((item) => item.value === o.startAt);
|
|
22
27
|
const startCategory = start >= 0 ? o.items[start].category : o.startCategory;
|
|
@@ -27,21 +32,26 @@ export class ListScreen {
|
|
|
27
32
|
}
|
|
28
33
|
/** Indexes of the entries shown now: all matches of the search, else the current category's, else all. */
|
|
29
34
|
visible() {
|
|
35
|
+
const key = this.query + '\0' + this.category;
|
|
36
|
+
if (this.shown?.key !== key)
|
|
37
|
+
this.shown = { key, indexes: this.matching() };
|
|
38
|
+
return this.shown.indexes;
|
|
39
|
+
}
|
|
40
|
+
matching() {
|
|
30
41
|
const all = this.o.items.map((_, i) => i);
|
|
31
42
|
if (this.query.trim()) {
|
|
32
43
|
const words = this.query.toLowerCase().split(/\s+/).filter(Boolean);
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
.join(' ')
|
|
38
|
-
.toLowerCase();
|
|
39
|
-
return words.every((w) => hay.includes(w));
|
|
40
|
-
});
|
|
44
|
+
const hays = (this.haystacks ??= this.o.items.map((it) => [it.label, Text.strip(it.hint ?? ''), it.description, it.keywords, it.section, this.categoryLabel(it.category)]
|
|
45
|
+
.join(' ')
|
|
46
|
+
.toLowerCase()));
|
|
47
|
+
return all.filter((i) => words.every((w) => hays[i].includes(w)));
|
|
41
48
|
}
|
|
42
49
|
const cat = this.o.categories?.[this.category];
|
|
43
50
|
return cat ? all.filter((i) => this.o.items[i].category === cat.id) : all;
|
|
44
51
|
}
|
|
52
|
+
categoryLabel(id) {
|
|
53
|
+
return this.o.categories?.find((c) => c.id === id)?.label ?? '';
|
|
54
|
+
}
|
|
45
55
|
rows(visible) {
|
|
46
56
|
const rows = [];
|
|
47
57
|
let section;
|
|
@@ -49,7 +59,7 @@ export class ListScreen {
|
|
|
49
59
|
for (const index of visible) {
|
|
50
60
|
const it = this.o.items[index];
|
|
51
61
|
const heading = searchAll
|
|
52
|
-
? [this.
|
|
62
|
+
? [this.categoryLabel(it.category), it.section].filter(Boolean).join(' › ')
|
|
53
63
|
: it.section;
|
|
54
64
|
if (heading && heading !== section)
|
|
55
65
|
rows.push({ kind: 'section', text: heading });
|
|
@@ -68,6 +78,35 @@ export class ListScreen {
|
|
|
68
78
|
const detailsRight = rest >= 100;
|
|
69
79
|
const detailsWidth = detailsRight ? Math.min(52, Math.floor(rest * 0.38)) : rest;
|
|
70
80
|
const listWidth = detailsRight ? rest - detailsWidth - 3 : rest;
|
|
81
|
+
const top = this.topLines(size.width, visible.length);
|
|
82
|
+
const details = this.detailsLines(visible[this.cursor], detailsWidth);
|
|
83
|
+
const bottomDetails = !detailsRight && size.height - top.length >= 14 ? details.slice(0, 6) : [];
|
|
84
|
+
const rows = this.rows(visible);
|
|
85
|
+
const room = size.height - top.length - (bottomDetails.length ? bottomDetails.length + 1 : 0);
|
|
86
|
+
// A list longer than the room keeps one row for "▲ / ▼ more".
|
|
87
|
+
const listHeight = rows.length > room ? room - 1 : room;
|
|
88
|
+
const listLines = this.listLines(visible, rows, listHeight, listWidth);
|
|
89
|
+
const sideLines = sideWidth ? this.sideLines(sideWidth) : [];
|
|
90
|
+
const body = [...top];
|
|
91
|
+
const height = Math.max(listLines.length, detailsRight ? details.length : 0, sideLines.length);
|
|
92
|
+
for (let i = 0; i < Math.min(height, size.height - top.length); i++) {
|
|
93
|
+
const side = sideWidth ? Text.fit(sideLines[i] ?? '', sideWidth) + ' ' + Theme.dim(Theme.glyph.vline) + ' ' : '';
|
|
94
|
+
const main = Text.fit(listLines[i] ?? '', listWidth);
|
|
95
|
+
const right = detailsRight ? ' ' + Theme.dim(Theme.glyph.vline) + ' ' + (details[i] ?? '') : '';
|
|
96
|
+
body.push(side + main + right);
|
|
97
|
+
}
|
|
98
|
+
if (bottomDetails.length) {
|
|
99
|
+
// The details sit at the bottom, whatever the length of the list.
|
|
100
|
+
while (body.length < size.height - bottomDetails.length - 1)
|
|
101
|
+
body.push(sideWidth
|
|
102
|
+
? Text.fit(sideLines[body.length - top.length] ?? '', sideWidth) + ' ' + Theme.dim(Theme.glyph.vline)
|
|
103
|
+
: '');
|
|
104
|
+
body.push(Theme.dim(' ' + Theme.glyph.line.repeat(size.width - 3)), ...bottomDetails.map((l) => ' ' + l));
|
|
105
|
+
}
|
|
106
|
+
return { path: this.o.path, status: this.o.status, body, keys: this.keys(), notice: this.notice };
|
|
107
|
+
}
|
|
108
|
+
/** The rows above the list: the tabs, the intro, the search box (with a blank row after them). */
|
|
109
|
+
topLines(width, matches) {
|
|
71
110
|
const top = [];
|
|
72
111
|
if (this.o.tabs) {
|
|
73
112
|
const row = ' ' +
|
|
@@ -77,26 +116,24 @@ export class ListScreen {
|
|
|
77
116
|
: Theme.muted(' ' + tab.label + ' '))
|
|
78
117
|
.join(' ') +
|
|
79
118
|
Theme.muted(' tab switches');
|
|
80
|
-
top.push(Text.truncate(row,
|
|
119
|
+
top.push(Text.truncate(row, width - 1), '');
|
|
81
120
|
}
|
|
82
121
|
const intro = typeof this.o.intro === 'string' ? [this.o.intro] : (this.o.intro ?? []);
|
|
83
122
|
for (const line of intro)
|
|
84
|
-
top.push(...Text.wrap(line,
|
|
123
|
+
top.push(...Text.wrap(line, width - 3).map((l) => ' ' + Theme.muted(l)));
|
|
85
124
|
if (this.searching || this.query)
|
|
86
125
|
top.push(' ' +
|
|
87
126
|
Theme.accent(Theme.glyph.search) +
|
|
88
127
|
' ' +
|
|
89
128
|
this.query +
|
|
90
129
|
(this.searching ? Theme.accent('▏') : '') +
|
|
91
|
-
Theme.muted(' ' +
|
|
130
|
+
Theme.muted(' ' + matches + ' match' + (matches === 1 ? '' : 'es')));
|
|
92
131
|
if (top.length)
|
|
93
132
|
top.push('');
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
// A list longer than the room keeps one row for "▲ / ▼ more".
|
|
99
|
-
const listHeight = rows.length > room ? room - 1 : room;
|
|
133
|
+
return top;
|
|
134
|
+
}
|
|
135
|
+
/** The rows of the list that fit: scrolled to keep the cursor in view, with "▲ above / ▼ more" under them. */
|
|
136
|
+
listLines(visible, rows, listHeight, listWidth) {
|
|
100
137
|
const cursorRow = rows.findIndex((r) => r.kind === 'item' && r.index === visible[this.cursor]);
|
|
101
138
|
if (cursorRow >= 0) {
|
|
102
139
|
// Keep the heading above the first entry in view, and the cursor inside the window.
|
|
@@ -122,24 +159,7 @@ export class ListScreen {
|
|
|
122
159
|
(below > 0 ? '▼ ' + below + ' more' : '') +
|
|
123
160
|
(this.searching || this.query ? '' : ' / search')));
|
|
124
161
|
}
|
|
125
|
-
|
|
126
|
-
const body = [...top];
|
|
127
|
-
const height = Math.max(listLines.length, detailsRight ? details.length : 0, sideLines.length);
|
|
128
|
-
for (let i = 0; i < Math.min(height, size.height - top.length); i++) {
|
|
129
|
-
const side = sideWidth ? Text.fit(sideLines[i] ?? '', sideWidth) + ' ' + Theme.dim(Theme.glyph.vline) + ' ' : '';
|
|
130
|
-
const main = Text.fit(listLines[i] ?? '', listWidth);
|
|
131
|
-
const right = detailsRight ? ' ' + Theme.dim(Theme.glyph.vline) + ' ' + (details[i] ?? '') : '';
|
|
132
|
-
body.push(side + main + right);
|
|
133
|
-
}
|
|
134
|
-
if (bottomDetails.length) {
|
|
135
|
-
// The details sit at the bottom, whatever the length of the list.
|
|
136
|
-
while (body.length < size.height - bottomDetails.length - 1)
|
|
137
|
-
body.push(sideWidth
|
|
138
|
-
? Text.fit(sideLines[body.length - top.length] ?? '', sideWidth) + ' ' + Theme.dim(Theme.glyph.vline)
|
|
139
|
-
: '');
|
|
140
|
-
body.push(Theme.dim(' ' + Theme.glyph.line.repeat(size.width - 3)), ...bottomDetails.map((l) => ' ' + l));
|
|
141
|
-
}
|
|
142
|
-
return { path: this.o.path, status: this.o.status, body, keys: this.keys(), notice: this.notice };
|
|
162
|
+
return listLines;
|
|
143
163
|
}
|
|
144
164
|
rowLine(row, visible, width) {
|
|
145
165
|
if (row.kind === 'section')
|
|
@@ -283,6 +303,14 @@ export class ListScreen {
|
|
|
283
303
|
const all = typeof actions === 'function' ? actions(this.currentCategory) : (actions ?? []);
|
|
284
304
|
return all.filter((a) => !a.applies || (value !== undefined && a.applies(value)));
|
|
285
305
|
}
|
|
306
|
+
/** The value under the cursor (undefined: the list is empty). */
|
|
307
|
+
get current() {
|
|
308
|
+
return this.valueAt(this.visible()[this.cursor]);
|
|
309
|
+
}
|
|
310
|
+
/** The text of the search (empty: none). */
|
|
311
|
+
get searchText() {
|
|
312
|
+
return this.query;
|
|
313
|
+
}
|
|
286
314
|
/** Keys are going into the search box (digits and letters are text, not shortcuts). */
|
|
287
315
|
get isSearching() {
|
|
288
316
|
return this.searching;
|
|
@@ -71,6 +71,8 @@ export interface ListOptions<T> {
|
|
|
71
71
|
/** Start on this entry (and its category). */
|
|
72
72
|
startAt?: T;
|
|
73
73
|
startCategory?: string;
|
|
74
|
+
/** Start with this search typed (it shows every match in all categories; Esc clears it). */
|
|
75
|
+
startQuery?: string;
|
|
74
76
|
/** Extra keys; a function picks them by the open category. */
|
|
75
77
|
actions?: ListAction<T>[] | ((category: string | undefined) => ListAction<T>[]);
|
|
76
78
|
notice?: string;
|
|
@@ -10,6 +10,8 @@ export interface Key {
|
|
|
10
10
|
export declare class ExitRequested extends Error {
|
|
11
11
|
constructor();
|
|
12
12
|
}
|
|
13
|
+
/** Whether this terminal is known to take synchronized updates (AGENT_SANDBOX_SYNC_UPDATE=1 or 0 overrides). */
|
|
14
|
+
export declare function supportsSyncUpdate(env?: NodeJS.ProcessEnv): boolean;
|
|
13
15
|
export declare class Terminal {
|
|
14
16
|
private readonly stdin;
|
|
15
17
|
private readonly stdout;
|
|
@@ -18,17 +20,22 @@ export declare class Terminal {
|
|
|
18
20
|
private queue;
|
|
19
21
|
private waiting;
|
|
20
22
|
private resizeHandler;
|
|
23
|
+
private readonly sync;
|
|
21
24
|
private readonly onKeypress;
|
|
22
25
|
private readonly onResize;
|
|
23
26
|
constructor(stdin?: NodeJS.ReadStream, stdout?: NodeJS.WriteStream);
|
|
24
27
|
get width(): number;
|
|
25
28
|
get height(): number;
|
|
29
|
+
/** Keys can be read from a real terminal here (the menu refuses to open without one). */
|
|
30
|
+
get interactive(): boolean;
|
|
26
31
|
/** Called after the window was resized (the screen draws itself again). */
|
|
27
32
|
onResized(handler: (() => void) | null): void;
|
|
28
33
|
start(): void;
|
|
29
34
|
/** Gives the terminal back exactly as it was (also on errors: callers use try/finally). */
|
|
30
35
|
stop(): void;
|
|
31
36
|
get running(): boolean;
|
|
37
|
+
/** Key presses are waiting to be read (the screen may skip a draw and show the result of the last one). */
|
|
38
|
+
get hasKeys(): boolean;
|
|
32
39
|
/** Draws a whole screen: `lines` are cut to the width and padded to the height; unchanged rows are not rewritten. */
|
|
33
40
|
render(lines: string[]): void;
|
|
34
41
|
/** The next key press. Ctrl+C rejects with ExitRequested. */
|
package/dist/cli/tui/terminal.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// The terminal while the menu owns it: the alternate screen (your scrollback stays as it was), raw keys, a cursor that
|
|
2
|
-
// is hidden, and redraws that only rewrite the rows that changed
|
|
3
|
-
// a command's own output;
|
|
2
|
+
// is hidden, and redraws that only rewrite the rows that changed, in one write (inside a synchronized update where the
|
|
3
|
+
// terminal has one), so nothing flickers. stop() hands the terminal back for a command's own output; start() takes it
|
|
4
|
+
// again.
|
|
4
5
|
import readline from 'node:readline';
|
|
5
6
|
import { Text } from './text.js';
|
|
6
7
|
/** Ctrl+C: leave the menu at once (callers let it propagate to the top). */
|
|
@@ -10,6 +11,17 @@ export class ExitRequested extends Error {
|
|
|
10
11
|
this.name = 'ExitPromptError';
|
|
11
12
|
}
|
|
12
13
|
}
|
|
14
|
+
/** DEC 2026: the terminal shows a frame only when it is complete. Others ignore it, so only these are asked. */
|
|
15
|
+
const SYNC_BEGIN = '\x1b[?2026h';
|
|
16
|
+
const SYNC_END = '\x1b[?2026l';
|
|
17
|
+
/** Whether this terminal is known to take synchronized updates (AGENT_SANDBOX_SYNC_UPDATE=1 or 0 overrides). */
|
|
18
|
+
export function supportsSyncUpdate(env = process.env) {
|
|
19
|
+
const forced = env.AGENT_SANDBOX_SYNC_UPDATE;
|
|
20
|
+
if (forced === '1' || forced === '0')
|
|
21
|
+
return forced === '1';
|
|
22
|
+
const program = env.TERM_PROGRAM ?? '';
|
|
23
|
+
return Boolean(env.WT_SESSION) || ['vscode', 'WezTerm', 'iTerm.app', 'ghostty', 'contour'].includes(program);
|
|
24
|
+
}
|
|
13
25
|
export class Terminal {
|
|
14
26
|
stdin;
|
|
15
27
|
stdout;
|
|
@@ -18,6 +30,7 @@ export class Terminal {
|
|
|
18
30
|
queue = [];
|
|
19
31
|
waiting = null;
|
|
20
32
|
resizeHandler = null;
|
|
33
|
+
sync = supportsSyncUpdate();
|
|
21
34
|
onKeypress = (str, key) => this.push(str, key);
|
|
22
35
|
onResize = () => {
|
|
23
36
|
this.frame = [];
|
|
@@ -33,6 +46,10 @@ export class Terminal {
|
|
|
33
46
|
get height() {
|
|
34
47
|
return Math.max(12, this.stdout.rows ?? 30);
|
|
35
48
|
}
|
|
49
|
+
/** Keys can be read from a real terminal here (the menu refuses to open without one). */
|
|
50
|
+
get interactive() {
|
|
51
|
+
return Boolean(this.stdin.isTTY);
|
|
52
|
+
}
|
|
36
53
|
/** Called after the window was resized (the screen draws itself again). */
|
|
37
54
|
onResized(handler) {
|
|
38
55
|
this.resizeHandler = handler;
|
|
@@ -66,21 +83,24 @@ export class Terminal {
|
|
|
66
83
|
get running() {
|
|
67
84
|
return this.active;
|
|
68
85
|
}
|
|
86
|
+
/** Key presses are waiting to be read (the screen may skip a draw and show the result of the last one). */
|
|
87
|
+
get hasKeys() {
|
|
88
|
+
return this.queue.length > 0;
|
|
89
|
+
}
|
|
69
90
|
/** Draws a whole screen: `lines` are cut to the width and padded to the height; unchanged rows are not rewritten. */
|
|
70
91
|
render(lines) {
|
|
71
92
|
const { width, height } = this;
|
|
72
93
|
// One column is left free: writing the last column can scroll older consoles.
|
|
73
94
|
const rows = Array.from({ length: height }, (_, i) => Text.fit(lines[i] ?? '', width - 1));
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
out = '\x1b[H\x1b[2J' + rows.map((r, i) => '\x1b[' + (i + 1) + ';1H' + r + '\x1b[0m').join('');
|
|
95
|
+
// A different height (or nothing drawn yet: after a resize or a start) repaints everything.
|
|
96
|
+
const repaint = this.frame.length !== rows.length;
|
|
97
|
+
const out = (repaint ? '\x1b[H\x1b[2J' : '') +
|
|
98
|
+
rows
|
|
99
|
+
.map((row, i) => (repaint || this.frame[i] !== row ? '\x1b[' + (i + 1) + ';1H' + row + '\x1b[0m' : ''))
|
|
100
|
+
.join('');
|
|
81
101
|
this.frame = rows;
|
|
82
102
|
if (out)
|
|
83
|
-
this.stdout.write(out);
|
|
103
|
+
this.stdout.write(this.sync ? SYNC_BEGIN + out + SYNC_END : out);
|
|
84
104
|
}
|
|
85
105
|
/** The next key press. Ctrl+C rejects with ExitRequested. */
|
|
86
106
|
key() {
|
|
@@ -6,12 +6,15 @@ export const DEFAULTS = {
|
|
|
6
6
|
audit: { enabled: false, days: 14, maxMb: 100, processes: true, files: true },
|
|
7
7
|
mappings: [],
|
|
8
8
|
sandbox: {
|
|
9
|
+
engine: 'windows-sandbox',
|
|
9
10
|
memoryMb: 'auto',
|
|
10
11
|
maxMemoryMb: 32768,
|
|
11
12
|
maxMemoryPercent: 80,
|
|
12
13
|
cpuLimit: 80,
|
|
13
14
|
pageFileMb: 16384,
|
|
14
15
|
reserveHostMb: 8192,
|
|
16
|
+
agentMemoryHeadroomMb: 'auto',
|
|
17
|
+
pressureResponse: true,
|
|
15
18
|
vGpu: false,
|
|
16
19
|
networking: true,
|
|
17
20
|
clipboard: true,
|
|
@@ -28,6 +31,8 @@ export const DEFAULTS = {
|
|
|
28
31
|
persistAgentState: true,
|
|
29
32
|
dataName: 'default',
|
|
30
33
|
markSandboxFiles: true,
|
|
34
|
+
contained: 'off',
|
|
35
|
+
containedMaxGb: 64,
|
|
31
36
|
warnDataGb: 50,
|
|
32
37
|
},
|
|
33
38
|
network: { blockPrivateRanges: true, allowOnly: [], blockHosts: [], forwardPorts: [], dns: [], proxy: '' },
|
|
@@ -89,7 +94,7 @@ export const DEFAULTS = {
|
|
|
89
94
|
sqlserver: { enabled: 'auto' },
|
|
90
95
|
},
|
|
91
96
|
attach: { enabled: true, reuseSession: true, auto: false, autoHide: false },
|
|
92
|
-
web: { enabled: false, port: 47800 },
|
|
97
|
+
web: { enabled: false, port: 47800, openOnLaunch: false },
|
|
93
98
|
agentCommands: { enabled: false, agents: 'auto' },
|
|
94
99
|
secrets: { strip: true, allow: [], patterns: [], warnFiles: true },
|
|
95
100
|
personalization: { enabled: true },
|
|
@@ -126,6 +131,9 @@ export const DEFAULTS = {
|
|
|
126
131
|
environment: {},
|
|
127
132
|
home: { env: { CODEX_HOME: 'codex' }, loginFiles: ['auth.json'], hostDir: '~/.codex' },
|
|
128
133
|
localState: { CODEX_SQLITE_HOME: 'sqlite' },
|
|
134
|
+
// Its own command sandbox keeps local users' passwords sealed with DPAPI: unreadable in the next sandbox
|
|
135
|
+
// ("CryptUnprotectData" on every command), so it sets that sandbox up again at each boot.
|
|
136
|
+
bootReset: ['.sandbox-secrets', '.sandbox\\setup_marker.json', '.sandbox\\deny_read_acl_state.json'],
|
|
129
137
|
resumeArguments: ['resume', '--last'],
|
|
130
138
|
},
|
|
131
139
|
gemini: {
|
|
@@ -23,12 +23,18 @@ export declare const ConfigSchema: z.ZodObject<{
|
|
|
23
23
|
optional: z.ZodOptional<z.ZodBoolean>;
|
|
24
24
|
}, z.core.$strict>>;
|
|
25
25
|
sandbox: z.ZodObject<{
|
|
26
|
+
engine: z.ZodEnum<{
|
|
27
|
+
"windows-sandbox": "windows-sandbox";
|
|
28
|
+
hcs: "hcs";
|
|
29
|
+
}>;
|
|
26
30
|
memoryMb: z.ZodUnion<readonly [z.ZodLiteral<"auto">, z.ZodNumber]>;
|
|
27
31
|
maxMemoryMb: z.ZodNumber;
|
|
28
32
|
maxMemoryPercent: z.ZodNumber;
|
|
29
33
|
cpuLimit: z.ZodUnion<readonly [z.ZodLiteral<"none">, z.ZodNumber]>;
|
|
30
34
|
pageFileMb: z.ZodNumber;
|
|
31
35
|
reserveHostMb: z.ZodNumber;
|
|
36
|
+
agentMemoryHeadroomMb: z.ZodUnion<readonly [z.ZodLiteral<"auto">, z.ZodLiteral<"none">, z.ZodNumber]>;
|
|
37
|
+
pressureResponse: z.ZodBoolean;
|
|
32
38
|
vGpu: z.ZodBoolean;
|
|
33
39
|
networking: z.ZodBoolean;
|
|
34
40
|
clipboard: z.ZodBoolean;
|
|
@@ -47,6 +53,11 @@ export declare const ConfigSchema: z.ZodObject<{
|
|
|
47
53
|
persistAgentState: z.ZodBoolean;
|
|
48
54
|
dataName: z.ZodString;
|
|
49
55
|
markSandboxFiles: z.ZodBoolean;
|
|
56
|
+
contained: z.ZodEnum<{
|
|
57
|
+
off: "off";
|
|
58
|
+
vhdx: "vhdx";
|
|
59
|
+
}>;
|
|
60
|
+
containedMaxGb: z.ZodNumber;
|
|
50
61
|
warnDataGb: z.ZodNumber;
|
|
51
62
|
}, z.core.$strict>;
|
|
52
63
|
network: z.ZodObject<{
|
|
@@ -65,6 +76,7 @@ export declare const ConfigSchema: z.ZodObject<{
|
|
|
65
76
|
provider: z.ZodEnum<{
|
|
66
77
|
nordvpn: "nordvpn";
|
|
67
78
|
"openvpn-file": "openvpn-file";
|
|
79
|
+
"wireguard-file": "wireguard-file";
|
|
68
80
|
}>;
|
|
69
81
|
protocol: z.ZodEnum<{
|
|
70
82
|
udp: "udp";
|
|
@@ -235,6 +247,7 @@ export declare const ConfigSchema: z.ZodObject<{
|
|
|
235
247
|
web: z.ZodObject<{
|
|
236
248
|
enabled: z.ZodBoolean;
|
|
237
249
|
port: z.ZodNumber;
|
|
250
|
+
openOnLaunch: z.ZodBoolean;
|
|
238
251
|
}, z.core.$strict>;
|
|
239
252
|
agentCommands: z.ZodObject<{
|
|
240
253
|
enabled: z.ZodBoolean;
|
|
@@ -301,6 +314,7 @@ export declare const ConfigSchema: z.ZodObject<{
|
|
|
301
314
|
hostDir: z.ZodOptional<z.ZodString>;
|
|
302
315
|
}, z.core.$strict>>;
|
|
303
316
|
localState: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
317
|
+
bootReset: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
304
318
|
resumeArguments: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
305
319
|
resumeOneArguments: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
306
320
|
}, z.core.$strict>>;
|
|
@@ -34,6 +34,15 @@ export const ConfigSchema = z
|
|
|
34
34
|
markSandboxFiles: z
|
|
35
35
|
.boolean()
|
|
36
36
|
.describe('Programs and scripts (.exe, .ps1, .bat, .cmd, .msi, .lnk ...) that appear or change in your project while a sandbox runs get Windows\' "downloaded from the internet" mark, so SmartScreen and PowerShell ask before they run on this PC.'),
|
|
37
|
+
contained: z
|
|
38
|
+
.enum(['off', 'vhdx'])
|
|
39
|
+
.describe('(beta) Keep the sandbox tools, state and logs inside one disk image file (vhdx) instead of loose folders, so scanning programs on this PC see one file. Not yet tried on a real PC. Turn it on with sandbox storage contained on (it moves your files and asks first); Windows asks for permission to mount the image when a sandbox starts. "off" = loose folders, as always. Yours only: a project file (.sandbox-config.json) cannot set it.'),
|
|
40
|
+
containedMaxGb: z
|
|
41
|
+
.number()
|
|
42
|
+
.int()
|
|
43
|
+
.min(8)
|
|
44
|
+
.max(4096)
|
|
45
|
+
.describe('(beta) Largest size, in GB, the disk image of storage.contained may grow to.'),
|
|
37
46
|
warnDataGb: z
|
|
38
47
|
.number()
|
|
39
48
|
.min(0)
|
|
@@ -78,7 +87,13 @@ export const LocalOverridesSchema = z
|
|
|
78
87
|
.describe('Extra folders (relative paths are relative to this file), e.g. a read-only data folder at another place in the sandbox. Folders outside the project are used only as your projects.allowOutsideMappings setting allows (by default you are asked once).'),
|
|
79
88
|
scripts: StringsSchema.describe('Scripts (.ps1 / .mjs / .cmd, relative to this file) run inside the sandbox before the agent.'),
|
|
80
89
|
// This PC's resources are yours to share: CPU and paging file (this PC's disk) are not a project's to set.
|
|
81
|
-
sandbox: SandboxSchema.omit({
|
|
90
|
+
sandbox: SandboxSchema.omit({
|
|
91
|
+
cpuLimit: true,
|
|
92
|
+
pageFileMb: true,
|
|
93
|
+
engine: true,
|
|
94
|
+
agentMemoryHeadroomMb: true,
|
|
95
|
+
pressureResponse: true,
|
|
96
|
+
}).partial(),
|
|
82
97
|
// A project may block more (the LAN, hosts); it never opens hosts, ports, DNS or a proxy.
|
|
83
98
|
network: NetworkSchema.pick({ blockPrivateRanges: true, blockHosts: true }).partial(),
|
|
84
99
|
// A project may turn the kill switch on, never off, and never choose a VPN, a server, a file or a login.
|
|
@@ -22,6 +22,7 @@ export declare const HarnessSchema: z.ZodObject<{
|
|
|
22
22
|
hostDir: z.ZodOptional<z.ZodString>;
|
|
23
23
|
}, z.core.$strict>>;
|
|
24
24
|
localState: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
25
|
+
bootReset: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
25
26
|
resumeArguments: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
26
27
|
resumeOneArguments: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
27
28
|
}, z.core.$strict>;
|
|
@@ -49,6 +49,11 @@ export const HarnessSchema = z
|
|
|
49
49
|
.record(z.string().regex(/^[A-Za-z_][A-Za-z0-9_]*$/), SubfolderSchema)
|
|
50
50
|
.optional()
|
|
51
51
|
.describe("Environment variable -> folder below the agent's own state folder (state\\<agent>) for SQLite databases. SQLite cannot run in a mapped folder, so the agent runs from a copy on the sandbox's disk (the variable points to it) that is copied from and back to that folder."),
|
|
52
|
+
bootReset: z
|
|
53
|
+
.array(SubfolderSchema)
|
|
54
|
+
.max(32)
|
|
55
|
+
.optional()
|
|
56
|
+
.describe("Files and folders below the agent's own state folder (state\\<agent>) that only work on the machine that wrote them (keys sealed with Windows DPAPI, local accounts it created). Every sandbox is a new machine, so they are deleted at each boot and the agent sets them up again."),
|
|
52
57
|
resumeArguments: StringsSchema.optional().describe('Arguments used when the agent is restarted in place (e.g. after an account switch) so it resumes the conversation.'),
|
|
53
58
|
resumeOneArguments: StringsSchema.optional().describe('Arguments that reopen one conversation, with {id} where its id goes (claude: --resume {id}). Used instead of resumeArguments when the conversation of a session is known.'),
|
|
54
59
|
})
|
|
@@ -7,12 +7,18 @@ export declare const MappingSchema: z.ZodObject<{
|
|
|
7
7
|
optional: z.ZodOptional<z.ZodBoolean>;
|
|
8
8
|
}, z.core.$strict>;
|
|
9
9
|
export declare const SandboxSchema: z.ZodObject<{
|
|
10
|
+
engine: z.ZodEnum<{
|
|
11
|
+
"windows-sandbox": "windows-sandbox";
|
|
12
|
+
hcs: "hcs";
|
|
13
|
+
}>;
|
|
10
14
|
memoryMb: z.ZodUnion<readonly [z.ZodLiteral<"auto">, z.ZodNumber]>;
|
|
11
15
|
maxMemoryMb: z.ZodNumber;
|
|
12
16
|
maxMemoryPercent: z.ZodNumber;
|
|
13
17
|
cpuLimit: z.ZodUnion<readonly [z.ZodLiteral<"none">, z.ZodNumber]>;
|
|
14
18
|
pageFileMb: z.ZodNumber;
|
|
15
19
|
reserveHostMb: z.ZodNumber;
|
|
20
|
+
agentMemoryHeadroomMb: z.ZodUnion<readonly [z.ZodLiteral<"auto">, z.ZodLiteral<"none">, z.ZodNumber]>;
|
|
21
|
+
pressureResponse: z.ZodBoolean;
|
|
16
22
|
vGpu: z.ZodBoolean;
|
|
17
23
|
networking: z.ZodBoolean;
|
|
18
24
|
clipboard: z.ZodBoolean;
|
|
@@ -16,6 +16,9 @@ export const MappingSchema = z.strictObject({
|
|
|
16
16
|
optional: z.boolean().optional().describe('true = skip it quietly when the host folder does not exist.'),
|
|
17
17
|
});
|
|
18
18
|
export const SandboxSchema = z.strictObject({
|
|
19
|
+
engine: z
|
|
20
|
+
.enum(['windows-sandbox', 'hcs'])
|
|
21
|
+
.describe('(alpha) What runs the sandbox. "windows-sandbox" = Windows Sandbox (the default: desktop, Windows Terminal, GPU, clipboard, audio, printers). "hcs" = a headless Hyper-V isolated Server Core container for agents (no desktop, GPU or clipboard); it needs Windows features and an image on this PC (sandbox engine check hcs lists what is missing), and starting it is not enabled yet in this alpha. sandbox engine shows what each engine can do. Yours only: a project file (.sandbox-config.json) cannot set it.'),
|
|
19
22
|
memoryMb: z
|
|
20
23
|
.union([z.literal('auto'), z.number().int().min(2048)])
|
|
21
24
|
.describe('Sandbox RAM in MB (>= 2048), or "auto": free RAM minus reserveHostMb, capped at maxMemoryMb.'),
|
|
@@ -35,10 +38,24 @@ export const SandboxSchema = z.strictObject({
|
|
|
35
38
|
.min(0)
|
|
36
39
|
.max(262144)
|
|
37
40
|
.describe('Size of the sandbox\'s paging file in MB, created at full size when it starts so it never grows while builds run (8 GB of its disk always stays free). Windows Sandbox starts with about 1 GB: parallel builds then fail with "The paging file is too small", and Windows grows the file under load. 0 = leave Windows\' own.'),
|
|
38
|
-
reserveHostMb: z
|
|
39
|
-
|
|
41
|
+
reserveHostMb: z
|
|
42
|
+
.number()
|
|
43
|
+
.int()
|
|
44
|
+
.nonnegative()
|
|
45
|
+
.describe('Memory always left for this PC when memoryMb is "auto": the sandbox gets at most (free RAM, and RAM plus paging file still unused) minus this.'),
|
|
46
|
+
agentMemoryHeadroomMb: z
|
|
47
|
+
.union([z.literal('auto'), z.literal('none'), z.number().int().min(0)])
|
|
48
|
+
.describe('Memory kept out of the agents reach inside the sandbox, in MB: everything the agents start (their builds, tests, tools) together may use at most the sandbox memory minus this; a runaway parallel build then gets out-of-memory errors in its own session instead of freezing or crashing the whole sandbox. "auto" = the larger of 2048 MB and 10 % of the sandbox memory; "none" = no limit. Yours only: a project file cannot change it.'),
|
|
49
|
+
pressureResponse: z
|
|
50
|
+
.boolean()
|
|
51
|
+
.describe('When the sandbox (or this PC) runs low on memory, slow the heaviest build programs down (lower priority) and, if that is not enough, pause the biggest compiler for a few seconds at a time, so heavy parallel builds slow down instead of closing the sandbox. Never touches the agents themselves. Yours only: a project file cannot change it.'),
|
|
52
|
+
vGpu: z
|
|
53
|
+
.boolean()
|
|
54
|
+
.describe("Virtual GPU. Off by default: Microsoft notes it widens the sandbox attack surface. The sandbox then uses this PC's graphics card, and with some graphics drivers heavy use can freeze the whole PC: turn it on only when a program in the sandbox needs the GPU (the mesa toolchain gives software OpenGL without it)."),
|
|
40
55
|
networking: z.boolean().describe('Internet access. false is the only hard network isolation Windows Sandbox offers.'),
|
|
41
|
-
clipboard: z
|
|
56
|
+
clipboard: z
|
|
57
|
+
.boolean()
|
|
58
|
+
.describe("Shared clipboard between this PC and the sandbox. Also lets an agent's copy (in sandbox attach) reach this PC's clipboard."),
|
|
42
59
|
audioInput: z.boolean().describe('Microphone access.'),
|
|
43
60
|
videoInput: z.boolean().describe('Camera access.'),
|
|
44
61
|
printerRedirection: z.boolean().describe('Printers from this PC.'),
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
export declare const VPN_PROVIDERS: readonly ["nordvpn", "openvpn-file"];
|
|
2
|
+
export declare const VPN_PROVIDERS: readonly ["nordvpn", "openvpn-file", "wireguard-file"];
|
|
3
3
|
export declare const VpnSchema: z.ZodObject<{
|
|
4
4
|
enabled: z.ZodBoolean;
|
|
5
5
|
provider: z.ZodEnum<{
|
|
6
6
|
nordvpn: "nordvpn";
|
|
7
7
|
"openvpn-file": "openvpn-file";
|
|
8
|
+
"wireguard-file": "wireguard-file";
|
|
8
9
|
}>;
|
|
9
10
|
protocol: z.ZodEnum<{
|
|
10
11
|
udp: "udp";
|