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
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
// Running the shared core's actions inside the menu: an operation's questions become the menu's dialogs (yes/no over
|
|
2
|
+
// the screen, a text field, the path picker, a list), its fields the settings editors, its progress the page's notice,
|
|
3
|
+
// and what it said so far is shown above its next question. The result is one notice line: what it did, or what went
|
|
4
|
+
// wrong and how to fix it. A link leaves the menu for what needs the terminal (attach, a start).
|
|
5
|
+
import { operationById } from '../../app/features/defs.js';
|
|
6
|
+
import { runDefinition } from '../../app/registry.js';
|
|
7
|
+
import { Cancelled, ioFromAsker, SchemaNode, toWireError, } from '../../app/kernel/index.js';
|
|
8
|
+
import { errMsg } from '../../core/util/index.js';
|
|
9
|
+
import { Theme } from '../tui/index.js';
|
|
10
|
+
import { askPath } from './settings/ask-path.js';
|
|
11
|
+
import { ValueEditor } from './settings/value-editor.js';
|
|
12
|
+
async function ask(app, where, q, said) {
|
|
13
|
+
const lines = [...said, ...(q.lines ?? []), ...('problem' in q && q.problem ? [Theme.warn(q.problem)] : [])];
|
|
14
|
+
const path = [...where];
|
|
15
|
+
switch (q.kind) {
|
|
16
|
+
case 'confirm': {
|
|
17
|
+
if (!q.typed)
|
|
18
|
+
return app.ask(q.title, lines, q.yes ?? 'Yes', q.danger ?? false);
|
|
19
|
+
const typed = await app.text({ path, label: 'Type "' + q.typed + '" to confirm', about: [q.title, ...lines] });
|
|
20
|
+
return typed?.trim().toLowerCase() === q.typed;
|
|
21
|
+
}
|
|
22
|
+
case 'choose':
|
|
23
|
+
return app.choose(path, [q.title, ...lines].join(' '), q.choices, q.initial);
|
|
24
|
+
case 'checklist': {
|
|
25
|
+
const picked = await app.list({
|
|
26
|
+
path,
|
|
27
|
+
intro: [q.title, ...lines],
|
|
28
|
+
multi: true,
|
|
29
|
+
items: q.choices.map((ch) => ({ ...ch, checked: q.checked?.includes(ch.value) ?? false })),
|
|
30
|
+
});
|
|
31
|
+
return picked.kind === 'multi' ? picked.values : undefined;
|
|
32
|
+
}
|
|
33
|
+
case 'path':
|
|
34
|
+
return askPath(app, {
|
|
35
|
+
path,
|
|
36
|
+
title: q.title,
|
|
37
|
+
about: lines,
|
|
38
|
+
kind: q.pathKind,
|
|
39
|
+
initial: q.initial,
|
|
40
|
+
literals: q.literals,
|
|
41
|
+
});
|
|
42
|
+
case 'text':
|
|
43
|
+
case 'secret':
|
|
44
|
+
return app.text({
|
|
45
|
+
path,
|
|
46
|
+
label: q.title,
|
|
47
|
+
about: lines,
|
|
48
|
+
initial: q.kind === 'text' ? q.initial : undefined,
|
|
49
|
+
allowEmpty: q.kind === 'text' ? q.allowEmpty : false,
|
|
50
|
+
masked: q.kind === 'secret',
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
/** Where a link goes in the menu: what needs the terminal is run on the normal screen. */
|
|
55
|
+
function follow(target) {
|
|
56
|
+
switch (target.kind) {
|
|
57
|
+
case 'terminal':
|
|
58
|
+
return { exit: { kind: 'run', argv: ['attach', target.session] } };
|
|
59
|
+
case 'start-agent':
|
|
60
|
+
return { exit: { kind: 'run', argv: ['launch', '--harness', target.agent] } };
|
|
61
|
+
case 'command':
|
|
62
|
+
return { exit: { kind: 'run', argv: [...target.argv] } };
|
|
63
|
+
case 'view':
|
|
64
|
+
return {};
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
export class MenuOperations {
|
|
68
|
+
app;
|
|
69
|
+
ctx;
|
|
70
|
+
constructor(app, ctx) {
|
|
71
|
+
this.app = app;
|
|
72
|
+
this.ctx = ctx;
|
|
73
|
+
}
|
|
74
|
+
/** Does what an action of a page says: follows a link, or asks for its fields and runs its operation. */
|
|
75
|
+
async perform(action, where, busy) {
|
|
76
|
+
if (action.kind === 'link')
|
|
77
|
+
return follow(action.target);
|
|
78
|
+
const def = operationById(action.op);
|
|
79
|
+
if (!def)
|
|
80
|
+
return { notice: Theme.error(Theme.glyph.cross + ' Unknown operation ' + action.op + '.') };
|
|
81
|
+
const answers = await this.fields(action, def, where);
|
|
82
|
+
if (!answers)
|
|
83
|
+
return {};
|
|
84
|
+
return { reload: true, notice: await this.run(def, { ...action.input, ...answers }, where, busy) };
|
|
85
|
+
}
|
|
86
|
+
/** The values of an action's fields, from the editors that fit them (undefined: one was backed out of). */
|
|
87
|
+
async fields(action, def, where) {
|
|
88
|
+
const answers = {};
|
|
89
|
+
const editor = new ValueEditor(this.app);
|
|
90
|
+
for (const field of action.fields ?? []) {
|
|
91
|
+
const node = new SchemaNode(def.input).child(field.name);
|
|
92
|
+
if (!node)
|
|
93
|
+
continue;
|
|
94
|
+
const edited = await editor.edit([...where, field.label], [...field.key], node, action.initial?.[field.name]);
|
|
95
|
+
if (!edited)
|
|
96
|
+
return undefined;
|
|
97
|
+
answers[field.name] = edited.value;
|
|
98
|
+
}
|
|
99
|
+
return answers;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Runs a definition with this input and returns the notice to show: its text (✓), the problem and its fix (✘), or
|
|
103
|
+
* undefined when a question was declined (nothing changed, nothing to say).
|
|
104
|
+
*/
|
|
105
|
+
async run(def, input, where, busy = () => undefined) {
|
|
106
|
+
const said = [];
|
|
107
|
+
const asker = async (q) => (await ask(this.app, where, q, said.splice(0)));
|
|
108
|
+
const io = ioFromAsker(asker, {
|
|
109
|
+
progress: (text) => busy(Theme.muted(text + '…')),
|
|
110
|
+
log: (text, tone) => said.push(tone === 'warn' || tone === 'danger' ? Theme.warn(text) : text),
|
|
111
|
+
});
|
|
112
|
+
try {
|
|
113
|
+
const output = await runDefinition(def.id, this.ctx, input, io);
|
|
114
|
+
const text = def.text?.(output);
|
|
115
|
+
return text ? Theme.ok(Theme.glyph.ok + ' ' + text) : undefined;
|
|
116
|
+
}
|
|
117
|
+
catch (e) {
|
|
118
|
+
if (e instanceof Cancelled)
|
|
119
|
+
return undefined;
|
|
120
|
+
const problem = toWireError(e);
|
|
121
|
+
if (problem.kind === 'bug')
|
|
122
|
+
return Theme.error(Theme.glyph.cross + ' ' + errMsg(e));
|
|
123
|
+
return (Theme.error(Theme.glyph.cross + ' ' + problem.message) + (problem.fix ? Theme.muted(' ' + problem.fix) : ''));
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export interface LiveOptions {
|
|
2
|
+
/** Fetches the process list (default: tasklist, run without blocking). */
|
|
3
|
+
readonly fetch?: () => Promise<string>;
|
|
4
|
+
/** The status line from the facts now (reads the cached process list and small files; never runs a program). */
|
|
5
|
+
readonly derive: () => string;
|
|
6
|
+
/** The line changed: draw again. */
|
|
7
|
+
readonly onChange: () => void;
|
|
8
|
+
readonly intervalMs?: number;
|
|
9
|
+
}
|
|
10
|
+
export declare class LiveStatus {
|
|
11
|
+
private readonly o;
|
|
12
|
+
private tasklist;
|
|
13
|
+
private text;
|
|
14
|
+
private timer;
|
|
15
|
+
private pending;
|
|
16
|
+
private running;
|
|
17
|
+
constructor(o: LiveOptions);
|
|
18
|
+
/** The status line as of the last refresh. */
|
|
19
|
+
line(): string;
|
|
20
|
+
/** Reads the process list now and derives the line (one fetch at a time; a caller during one waits for it). */
|
|
21
|
+
refresh(): Promise<void>;
|
|
22
|
+
private derive;
|
|
23
|
+
/** Starts keeping the line fresh and answers the host's process questions from it (until stop). */
|
|
24
|
+
start(): Promise<void>;
|
|
25
|
+
/** Stops; the host's questions run their own programs again (a command that runs after the menu needs the truth). */
|
|
26
|
+
stop(): void;
|
|
27
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
// What the menu shows about the running sandbox (the status line), kept fresh in the background. Drawing and keys only
|
|
2
|
+
// read the last copy: the process list is fetched without blocking (every few seconds, and after an action), and the
|
|
3
|
+
// screen is told when what it shows has changed. While it runs, the host's own "is the sandbox running?" questions are
|
|
4
|
+
// answered from the same copy, so no page waits for a child process.
|
|
5
|
+
import { sandboxStatus } from '../../app/features/sandbox/index.js';
|
|
6
|
+
import { readTasklistAsync, useTasklistCache } from '../../host/sandbox/index.js';
|
|
7
|
+
/** The same rule as the web's live status: the sandbox status query's interval. */
|
|
8
|
+
const DEFAULT_INTERVAL_MS = sandboxStatus.live?.everyMs ?? 2500;
|
|
9
|
+
export class LiveStatus {
|
|
10
|
+
o;
|
|
11
|
+
tasklist;
|
|
12
|
+
text = '';
|
|
13
|
+
timer;
|
|
14
|
+
pending;
|
|
15
|
+
running = false;
|
|
16
|
+
constructor(o) {
|
|
17
|
+
this.o = o;
|
|
18
|
+
}
|
|
19
|
+
/** The status line as of the last refresh. */
|
|
20
|
+
line() {
|
|
21
|
+
return this.text;
|
|
22
|
+
}
|
|
23
|
+
/** Reads the process list now and derives the line (one fetch at a time; a caller during one waits for it). */
|
|
24
|
+
refresh() {
|
|
25
|
+
this.pending ??= (async () => {
|
|
26
|
+
try {
|
|
27
|
+
const list = await (this.o.fetch ?? readTasklistAsync)();
|
|
28
|
+
// Stopped meanwhile: a command may be running, and nothing here may touch the host's facts any more.
|
|
29
|
+
if (!this.running)
|
|
30
|
+
return;
|
|
31
|
+
this.tasklist = list;
|
|
32
|
+
this.derive();
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
// The line keeps what it showed; the next refresh tries again.
|
|
36
|
+
}
|
|
37
|
+
finally {
|
|
38
|
+
this.pending = undefined;
|
|
39
|
+
}
|
|
40
|
+
})();
|
|
41
|
+
return this.pending;
|
|
42
|
+
}
|
|
43
|
+
derive() {
|
|
44
|
+
const next = this.o.derive();
|
|
45
|
+
if (next === this.text)
|
|
46
|
+
return;
|
|
47
|
+
this.text = next;
|
|
48
|
+
if (this.running)
|
|
49
|
+
this.o.onChange();
|
|
50
|
+
}
|
|
51
|
+
/** Starts keeping the line fresh and answers the host's process questions from it (until stop). */
|
|
52
|
+
async start() {
|
|
53
|
+
if (this.running)
|
|
54
|
+
return;
|
|
55
|
+
this.running = true;
|
|
56
|
+
useTasklistCache(() => this.tasklist);
|
|
57
|
+
this.timer = setInterval(() => void this.refresh(), this.o.intervalMs ?? DEFAULT_INTERVAL_MS);
|
|
58
|
+
this.timer.unref();
|
|
59
|
+
await this.refresh();
|
|
60
|
+
}
|
|
61
|
+
/** Stops; the host's questions run their own programs again (a command that runs after the menu needs the truth). */
|
|
62
|
+
stop() {
|
|
63
|
+
this.running = false;
|
|
64
|
+
clearInterval(this.timer);
|
|
65
|
+
this.timer = undefined;
|
|
66
|
+
useTasklistCache(null);
|
|
67
|
+
this.tasklist = undefined;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import type { MenuView } from './shell.js';
|
|
3
|
+
declare const MenuStateSchema: z.ZodObject<{
|
|
4
|
+
section: z.ZodString;
|
|
5
|
+
screens: z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
6
|
+
category: z.ZodOptional<z.ZodString>;
|
|
7
|
+
search: z.ZodOptional<z.ZodString>;
|
|
8
|
+
}, z.core.$strict>>;
|
|
9
|
+
}, z.core.$strict>;
|
|
10
|
+
type MenuState = z.output<typeof MenuStateSchema>;
|
|
11
|
+
/** The view as it is stored: the section by name, so a menu with other sections still finds its way. */
|
|
12
|
+
export declare function viewToState(view: MenuView, labels: readonly string[]): MenuState;
|
|
13
|
+
/** A stored state as a view; a section that no longer exists falls back to the first. */
|
|
14
|
+
export declare function stateToView(state: MenuState, labels: readonly string[]): MenuView;
|
|
15
|
+
/** The view the last run left (undefined when there is none or the file is not valid). */
|
|
16
|
+
export declare function readMenuView(labels: readonly string[], dir?: string): MenuView | undefined;
|
|
17
|
+
/** Remembers the view for the next run. Never fails the menu. */
|
|
18
|
+
export declare function saveMenuView(view: MenuView, labels: readonly string[], dir?: string): void;
|
|
19
|
+
export {};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
// Where the menu was left, kept in ~/.agent-sandbox/menu-state.json: the open section and, for each section, its
|
|
2
|
+
// category and search. A convenience only: a missing, invalid or unwritable file means the menu opens on Agents.
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { z } from 'zod';
|
|
5
|
+
import { userDir } from '../../core/config/index.js';
|
|
6
|
+
import { JsonFile } from '../../shared/io/index.js';
|
|
7
|
+
const ScreenSchema = z.strictObject({
|
|
8
|
+
category: z.string().max(100).optional(),
|
|
9
|
+
search: z.string().max(200).optional(),
|
|
10
|
+
});
|
|
11
|
+
const MenuStateSchema = z.strictObject({
|
|
12
|
+
section: z.string().max(40),
|
|
13
|
+
screens: z.record(z.string().max(40), ScreenSchema),
|
|
14
|
+
});
|
|
15
|
+
function stateFile(dir) {
|
|
16
|
+
return new JsonFile(MenuStateSchema, path.join(dir, 'menu-state.json'));
|
|
17
|
+
}
|
|
18
|
+
/** The view as it is stored: the section by name, so a menu with other sections still finds its way. */
|
|
19
|
+
export function viewToState(view, labels) {
|
|
20
|
+
const screens = {};
|
|
21
|
+
for (const [label, screen] of Object.entries(view.screens))
|
|
22
|
+
if (labels.includes(label) && (screen.category || screen.search))
|
|
23
|
+
screens[label] = screen;
|
|
24
|
+
return { section: labels[view.section] ?? labels[0] ?? '', screens };
|
|
25
|
+
}
|
|
26
|
+
/** A stored state as a view; a section that no longer exists falls back to the first. */
|
|
27
|
+
export function stateToView(state, labels) {
|
|
28
|
+
const section = labels.indexOf(state.section);
|
|
29
|
+
return {
|
|
30
|
+
section: section < 0 ? 0 : section,
|
|
31
|
+
screens: Object.fromEntries(Object.entries(state.screens).filter(([label]) => labels.includes(label))),
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
/** The view the last run left (undefined when there is none or the file is not valid). */
|
|
35
|
+
export function readMenuView(labels, dir = userDir()) {
|
|
36
|
+
try {
|
|
37
|
+
const state = stateFile(dir).read();
|
|
38
|
+
return state ? stateToView(state, labels) : undefined;
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
// The state is a convenience: an unreadable file counts as none.
|
|
42
|
+
return undefined;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
/** Remembers the view for the next run. Never fails the menu. */
|
|
46
|
+
export function saveMenuView(view, labels, dir = userDir()) {
|
|
47
|
+
try {
|
|
48
|
+
stateFile(dir).write(viewToState(view, labels));
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
// Not remembering is fine.
|
|
52
|
+
}
|
|
53
|
+
}
|
package/dist/cli/menu/menu.d.ts
CHANGED
|
@@ -1,9 +1,18 @@
|
|
|
1
1
|
import type { Context } from '../commands/context.js';
|
|
2
|
+
import { Terminal } from '../tui/index.js';
|
|
3
|
+
/** What a test may replace: the terminal, the process list fetch and how often it is fetched. */
|
|
4
|
+
export interface MenuOptions {
|
|
5
|
+
readonly terminal?: Terminal;
|
|
6
|
+
readonly fetchTasklist?: () => Promise<string>;
|
|
7
|
+
readonly refreshMs?: number;
|
|
8
|
+
}
|
|
2
9
|
export declare class Menu {
|
|
3
10
|
private readonly ctx;
|
|
4
11
|
private readonly runArgv;
|
|
5
12
|
private readonly app;
|
|
6
|
-
|
|
13
|
+
private readonly live;
|
|
14
|
+
constructor(ctx: Context, runArgv: (argv: string[]) => Promise<number>, options?: MenuOptions);
|
|
15
|
+
/** The status line from the facts now: only ever called by the background refresh, never by a draw or a key. */
|
|
7
16
|
private status;
|
|
8
17
|
/** The sections, in order. */
|
|
9
18
|
private shell;
|
package/dist/cli/menu/menu.js
CHANGED
|
@@ -11,7 +11,7 @@ import { lookAtSandbox } from '../commands/shared-use.js';
|
|
|
11
11
|
import { commandLine } from '../history.js';
|
|
12
12
|
import { commandSpec } from '../manifest.js';
|
|
13
13
|
import { AgentCommandsService, LogsService } from '../services/index.js';
|
|
14
|
-
import { App, ExitRequested, Frame, Text, Theme } from '../tui/index.js';
|
|
14
|
+
import { App, ExitRequested, Frame, Terminal, Text, Theme } from '../tui/index.js';
|
|
15
15
|
import { AccountsPage } from './pages/accounts-page.js';
|
|
16
16
|
import { AgentsPage } from './pages/agents-page.js';
|
|
17
17
|
import { AppsPage } from './pages/apps-page.js';
|
|
@@ -19,19 +19,30 @@ import { MaintenancePage } from './pages/maintenance-page.js';
|
|
|
19
19
|
import { SandboxPage } from './pages/sandbox-page.js';
|
|
20
20
|
import { SessionsPage } from './pages/sessions-page.js';
|
|
21
21
|
import { SettingsPage } from './pages/settings-page.js';
|
|
22
|
-
import { ConfigFile } from '
|
|
22
|
+
import { ConfigFile } from '../../app/features/settings/index.js';
|
|
23
23
|
import { Draft } from './settings/draft.js';
|
|
24
|
-
import {
|
|
25
|
-
|
|
24
|
+
import { LiveStatus } from './live.js';
|
|
25
|
+
import { readMenuView, saveMenuView } from './memory.js';
|
|
26
|
+
import { SECTION_LABELS, Shell } from './shell.js';
|
|
27
|
+
/** Where the menu was last left: it opens there again (also in a later run, from menu-state.json). */
|
|
26
28
|
let lastView;
|
|
27
29
|
export class Menu {
|
|
28
30
|
ctx;
|
|
29
31
|
runArgv;
|
|
30
|
-
app
|
|
31
|
-
|
|
32
|
+
app;
|
|
33
|
+
live;
|
|
34
|
+
constructor(ctx, runArgv, options = {}) {
|
|
32
35
|
this.ctx = ctx;
|
|
33
36
|
this.runArgv = runArgv;
|
|
34
|
-
this.app
|
|
37
|
+
this.app = new App(options.terminal ?? new Terminal());
|
|
38
|
+
this.live = new LiveStatus({
|
|
39
|
+
fetch: options.fetchTasklist,
|
|
40
|
+
derive: () => this.status(),
|
|
41
|
+
onChange: () => this.app.requestRedraw(),
|
|
42
|
+
intervalMs: options.refreshMs,
|
|
43
|
+
});
|
|
44
|
+
this.app.status = () => this.live.line();
|
|
45
|
+
this.app.afterAction = () => this.live.refresh();
|
|
35
46
|
try {
|
|
36
47
|
Frame.version =
|
|
37
48
|
JSON.parse(fs.readFileSync(path.join(ctx.packageRoot, 'package.json'), 'utf8'))
|
|
@@ -41,6 +52,7 @@ export class Menu {
|
|
|
41
52
|
/* no version shown */
|
|
42
53
|
}
|
|
43
54
|
}
|
|
55
|
+
/** The status line from the facts now: only ever called by the background refresh, never by a draw or a key. */
|
|
44
56
|
status() {
|
|
45
57
|
const folder = Theme.muted(Text.middle(process.cwd(), 70));
|
|
46
58
|
if (!isSandboxRunning())
|
|
@@ -77,18 +89,22 @@ export class Menu {
|
|
|
77
89
|
}
|
|
78
90
|
/** Runs the menu until you leave it, or until a command that takes over the terminal (attach) has run. */
|
|
79
91
|
async start() {
|
|
80
|
-
if (!
|
|
92
|
+
if (!this.app.terminal.interactive) {
|
|
81
93
|
console.log('The menu needs an interactive terminal. Run sandbox --help for the commands.');
|
|
82
94
|
return 1;
|
|
83
95
|
}
|
|
84
96
|
try {
|
|
85
97
|
const shell = this.shell();
|
|
86
|
-
await
|
|
98
|
+
await this.live.start();
|
|
99
|
+
await shell.restore(lastView ?? readMenuView(SECTION_LABELS) ?? { section: 0, screens: {} });
|
|
87
100
|
for (;;) {
|
|
88
101
|
const exit = await this.app.show(shell);
|
|
89
102
|
lastView = shell.view();
|
|
103
|
+
saveMenuView(lastView, SECTION_LABELS);
|
|
90
104
|
if (exit.kind === 'quit')
|
|
91
105
|
return 0;
|
|
106
|
+
// A command (or a log) runs on its own facts, not on the menu's copy.
|
|
107
|
+
this.live.stop();
|
|
92
108
|
if (exit.kind === 'view')
|
|
93
109
|
await this.view(exit.file);
|
|
94
110
|
else {
|
|
@@ -96,6 +112,7 @@ export class Menu {
|
|
|
96
112
|
if (code !== undefined)
|
|
97
113
|
return code;
|
|
98
114
|
}
|
|
115
|
+
await this.live.start();
|
|
99
116
|
await shell.reload();
|
|
100
117
|
}
|
|
101
118
|
}
|
|
@@ -106,6 +123,7 @@ export class Menu {
|
|
|
106
123
|
throw e;
|
|
107
124
|
}
|
|
108
125
|
finally {
|
|
126
|
+
this.live.stop();
|
|
109
127
|
this.app.close();
|
|
110
128
|
}
|
|
111
129
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Context } from '../../commands/context.js';
|
|
2
2
|
import { type App, type Category, type ListAction, type ListOptions, type ListResult } from '../../tui/index.js';
|
|
3
|
-
import type { ConfigFile } from '
|
|
3
|
+
import type { ConfigFile } from '../../../app/features/settings/index.js';
|
|
4
4
|
import type { Draft } from '../settings/draft.js';
|
|
5
5
|
import { ListPage, type Outcome } from './list-page.js';
|
|
6
6
|
export type WindowChoice = 'config' | 'hide' | 'show';
|
|
@@ -46,6 +46,8 @@ export declare class AgentsPage extends ListPage<string> {
|
|
|
46
46
|
private window;
|
|
47
47
|
private folder;
|
|
48
48
|
private model;
|
|
49
|
+
/** What load() looked up (programs on PATH, the history file): not asked again for every list that is built. */
|
|
50
|
+
private facts;
|
|
49
51
|
constructor(app: App, ctx: Context,
|
|
50
52
|
/** Your own config file and its unsaved changes: where "Add an agent" writes to. */
|
|
51
53
|
file: ConfigFile, draft: Draft);
|
|
@@ -11,7 +11,7 @@ import { commandSpec } from '../../manifest.js';
|
|
|
11
11
|
import { Text, Theme, } from '../../tui/index.js';
|
|
12
12
|
import { AddAgent, makeDefaultAgent, removeAgent } from '../add-agent.js';
|
|
13
13
|
import { CommandForm } from '../command-form.js';
|
|
14
|
-
import { askPath } from '../settings/path
|
|
14
|
+
import { askPath } from '../settings/ask-path.js';
|
|
15
15
|
import { SeveralAgents } from '../several.js';
|
|
16
16
|
import { ListPage } from './list-page.js';
|
|
17
17
|
/** The agents of `harnesses` that are not built in. Pure. */
|
|
@@ -195,6 +195,8 @@ export class AgentsPage extends ListPage {
|
|
|
195
195
|
window = 'config';
|
|
196
196
|
folder = process.cwd();
|
|
197
197
|
model;
|
|
198
|
+
/** What load() looked up (programs on PATH, the history file): not asked again for every list that is built. */
|
|
199
|
+
facts;
|
|
198
200
|
constructor(app, ctx,
|
|
199
201
|
/** Your own config file and its unsaved changes: where "Add an agent" writes to. */
|
|
200
202
|
file, draft) {
|
|
@@ -220,12 +222,14 @@ export class AgentsPage extends ListPage {
|
|
|
220
222
|
}
|
|
221
223
|
current() {
|
|
222
224
|
const harnesses = this.harnesses();
|
|
223
|
-
|
|
225
|
+
if (!this.facts)
|
|
226
|
+
throw new Error('The agents tab was not loaded');
|
|
227
|
+
const { commands, last } = this.facts;
|
|
224
228
|
return {
|
|
225
229
|
folder: this.folder,
|
|
226
230
|
defaultAgent: this.file.userConfig().defaultHarness,
|
|
227
231
|
agents: Object.keys(harnesses).map((name) => ({ name, ready: this.installed(name, harnesses) })),
|
|
228
|
-
last
|
|
232
|
+
last,
|
|
229
233
|
attach: this.attach,
|
|
230
234
|
window: this.window,
|
|
231
235
|
hostAgents: hostAgentsToShow(commands.enabled, commands.found),
|
|
@@ -236,9 +240,12 @@ export class AgentsPage extends ListPage {
|
|
|
236
240
|
initialFocus() {
|
|
237
241
|
return 'agent:' + this.file.userConfig().defaultHarness;
|
|
238
242
|
}
|
|
239
|
-
load() {
|
|
243
|
+
async load() {
|
|
244
|
+
this.facts = {
|
|
245
|
+
commands: await new AgentCommandsService(this.ctx).statusAsync(),
|
|
246
|
+
last: readHistory()[0]?.argv,
|
|
247
|
+
};
|
|
240
248
|
this.model = this.current();
|
|
241
|
-
return Promise.resolve();
|
|
242
249
|
}
|
|
243
250
|
options() {
|
|
244
251
|
this.model = this.current();
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type App, type ListOptions, type ListResult } from '../../tui/index.js';
|
|
2
2
|
import { AppsModel } from '../apps.js';
|
|
3
|
-
import type { ConfigFile } from '
|
|
3
|
+
import type { ConfigFile } from '../../../app/features/settings/index.js';
|
|
4
4
|
import type { Draft } from '../settings/draft.js';
|
|
5
5
|
import { type Scope } from './scopes.js';
|
|
6
6
|
import { ListPage, type Outcome } from './list-page.js';
|
|
@@ -22,5 +22,7 @@ export declare class AppsPage extends ListPage<string> {
|
|
|
22
22
|
protected options(): ListOptions<string>;
|
|
23
23
|
/** Every tick is staged as it happens, so leaving or saving always sees it. */
|
|
24
24
|
protected afterKey(): Step<ShellExit>;
|
|
25
|
+
/** Opens the GitHub request form in the browser and says where it is. */
|
|
26
|
+
private request;
|
|
25
27
|
protected act(result: ListResult<string>): Promise<Outcome<string>>;
|
|
26
28
|
}
|
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
// scopes like Settings: apps for every project, or for this project only.
|
|
3
3
|
import { errMsg } from '../../../core/util/index.js';
|
|
4
4
|
import { Theme } from '../../tui/index.js';
|
|
5
|
-
import {
|
|
5
|
+
import { openIssuePage } from '../../../host/web/index.js';
|
|
6
|
+
import { AppsModel, requestAppUrl } from '../apps.js';
|
|
6
7
|
import { ValueEditor } from '../settings/value-editor.js';
|
|
7
8
|
import { SCOPES, scopeStatus } from './scopes.js';
|
|
8
9
|
import { ListPage } from './list-page.js';
|
|
@@ -17,7 +18,10 @@ export function appsOptions(model, file, draft, scope) {
|
|
|
17
18
|
enterTicks: true,
|
|
18
19
|
categories: model.categories(),
|
|
19
20
|
items: model.items(draft),
|
|
20
|
-
actions:
|
|
21
|
+
actions: [
|
|
22
|
+
...(file.isProject ? [] : [{ key: 'c', label: 'your own programs' }]),
|
|
23
|
+
{ key: 'r', label: 'request an app' },
|
|
24
|
+
],
|
|
21
25
|
};
|
|
22
26
|
}
|
|
23
27
|
export class AppsPage extends ListPage {
|
|
@@ -50,12 +54,25 @@ export class AppsPage extends ListPage {
|
|
|
50
54
|
this.model.stageTicks(this.draft, this.ticked());
|
|
51
55
|
return;
|
|
52
56
|
}
|
|
57
|
+
/** Opens the GitHub request form in the browser and says where it is. */
|
|
58
|
+
request() {
|
|
59
|
+
const url = requestAppUrl();
|
|
60
|
+
try {
|
|
61
|
+
openIssuePage(url);
|
|
62
|
+
return Theme.ok(Theme.glyph.ok + ' Opened the request form in your browser: ') + Theme.muted(url);
|
|
63
|
+
}
|
|
64
|
+
catch (e) {
|
|
65
|
+
return Theme.error(Theme.glyph.cross + ' ' + errMsg(e)) + Theme.muted(' Open it yourself: ' + url);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
53
68
|
async act(result) {
|
|
54
69
|
this.model.stageTicks(this.draft, this.ticked());
|
|
55
70
|
if (result.kind === 'tab') {
|
|
56
71
|
this.scope = SCOPES[result.index].scope;
|
|
57
72
|
return {};
|
|
58
73
|
}
|
|
74
|
+
if (result.kind === 'action' && result.key === 'r')
|
|
75
|
+
return { notice: this.request() };
|
|
59
76
|
if (result.kind !== 'action' || result.key !== 'c')
|
|
60
77
|
return {};
|
|
61
78
|
const node = this.file.schema.child('apps')?.child('custom');
|
|
@@ -20,6 +20,14 @@ export declare abstract class ListPage<T> implements Page {
|
|
|
20
20
|
private focused;
|
|
21
21
|
/** The entry that was last acted on: the cursor returns to it when the section opens again. */
|
|
22
22
|
private lastFocus;
|
|
23
|
+
/** A search to start the next list with (restored from the last run); used once. */
|
|
24
|
+
private pendingQuery;
|
|
25
|
+
/** The data has arrived at least once (until then the list is "Loading…"). */
|
|
26
|
+
private loaded;
|
|
27
|
+
/** Counts loads, so that a slow one that was overtaken does not replace newer data. */
|
|
28
|
+
private generation;
|
|
29
|
+
/** A category asked for before the data arrived: it opens when it does. */
|
|
30
|
+
private wantedCategory;
|
|
23
31
|
constructor(app: App);
|
|
24
32
|
/** Loads the data the list shows (called when the tab opens and after actions that change it). */
|
|
25
33
|
protected abstract load(): Promise<void>;
|
|
@@ -29,9 +37,15 @@ export declare abstract class ListPage<T> implements Page {
|
|
|
29
37
|
protected initialFocus(): T | undefined;
|
|
30
38
|
/** Does what the list returned. */
|
|
31
39
|
protected abstract act(result: ListResult<T>): Promise<Outcome<T>>;
|
|
40
|
+
/** The data has not arrived yet (the tab shows "Loading…"). */
|
|
41
|
+
get loading(): boolean;
|
|
32
42
|
get capturing(): boolean;
|
|
33
43
|
/** The id of the open category, if the list has any. */
|
|
34
44
|
get category(): string | undefined;
|
|
45
|
+
/** The search typed in the list ('' when none). */
|
|
46
|
+
get search(): string;
|
|
47
|
+
/** Shows the list with this search typed (the menu opens on the search it was left on). */
|
|
48
|
+
restoreSearch(text: string): void;
|
|
35
49
|
categories(): readonly Category[];
|
|
36
50
|
selectCategory(id: string): Promise<void>;
|
|
37
51
|
setFocus(list: boolean): void;
|
|
@@ -41,7 +55,20 @@ export declare abstract class ListPage<T> implements Page {
|
|
|
41
55
|
private build;
|
|
42
56
|
/** The entries ticked in a multi-select list. */
|
|
43
57
|
protected ticked(): T[];
|
|
58
|
+
/** Loads the data again; a slow load does not hold up the keys (the tab keeps what it showed, then updates). */
|
|
44
59
|
open(): Promise<void>;
|
|
60
|
+
/**
|
|
61
|
+
* Loads the data and waits for it at most QUICK_LOAD_MS. In time, the list is built here (`build`) or by the caller;
|
|
62
|
+
* later, the list is built when the data arrives, on the entry and search the user has moved to meanwhile.
|
|
63
|
+
*/
|
|
64
|
+
private reload;
|
|
65
|
+
private loadData;
|
|
66
|
+
/** Back on the entry used last, when it is still in the category that is open. */
|
|
67
|
+
private rebuildOpened;
|
|
68
|
+
/** Data that came after the keys stopped waiting: the cursor and the search stay where the user moved them. */
|
|
69
|
+
private rebuildLate;
|
|
70
|
+
private rebuildOn;
|
|
71
|
+
private openWantedCategory;
|
|
45
72
|
/** Builds the list again, on `focus` when it is still there. */
|
|
46
73
|
protected rebuild(focus: T | undefined, notice?: string): void;
|
|
47
74
|
/** Shows `text` now, before slow work starts. */
|