windows-development-sandbox 1.7.0 → 1.9.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 +10 -0
- 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 +47 -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 +19 -3
- package/dist/cli/commands/web.js +2 -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 +8 -0
- package/dist/core/schema/config.d.ts +13 -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 +3 -3
- 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 +2 -1
- 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 +61 -0
- package/dist/guest/governor/decide.js +182 -0
- package/dist/guest/governor/governor.d.ts +42 -0
- package/dist/guest/governor/governor.js +214 -0
- package/dist/guest/governor/index.d.ts +2 -0
- package/dist/guest/governor/index.js +2 -0
- package/dist/guest/runtime/csc.d.ts +1 -0
- package/dist/guest/runtime/csc.js +1 -0
- package/dist/guest/sessions/viewer.js +3 -1
- 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 +40 -0
- package/dist/host/life/host-memory.js +137 -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 +54 -0
- package/dist/host/life/watchdog.js +108 -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 +69 -8
- package/dist/runtime/daemon.js +1058 -624
- package/dist/runtime/db.js +69 -8
- package/dist/runtime/main.js +624 -182
- package/dist/runtime/netproxy.js +69 -8
- package/dist/runtime/view.js +87 -13
- 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/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 +329 -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/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 +7 -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/memory/index.d.ts +1 -0
- package/dist/shared/memory/index.js +1 -0
- package/dist/shared/memory/policy.d.ts +33 -0
- package/dist/shared/memory/policy.js +55 -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 +107 -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 +34 -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 +398 -0
- package/sandbox/csharp/PtyHost.cs +111 -5
- package/schemas/config.schema.json +60 -6
- 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,179 @@
|
|
|
1
|
+
// Settings: every setting of your own file (all projects) or of this folder's .sandbox-config.json (this project), read
|
|
2
|
+
// from the config schema through Fields, with get, set and reset. Pure: schemas and the view; the rows are made on the
|
|
3
|
+
// Node side (settings-rows.ts) because the config schema is, and secrets never leave it unmasked.
|
|
4
|
+
import { z } from 'zod';
|
|
5
|
+
import { action, defineOperation, defineQuery, defineView, FieldSchema, link, valueText, } from '../../kernel/index.js';
|
|
6
|
+
export const ScopeSchema = z
|
|
7
|
+
.enum(['user', 'project'])
|
|
8
|
+
.describe("Your own settings (all projects) or this folder's .sandbox-config.json (this project)");
|
|
9
|
+
const KeySchema = z
|
|
10
|
+
.string()
|
|
11
|
+
.regex(/^[A-Za-z0-9_$-]+(\.[A-Za-z0-9_$-]+)*$/)
|
|
12
|
+
.max(200)
|
|
13
|
+
.describe('The setting, e.g. sandbox.memoryMb');
|
|
14
|
+
/** One setting as every surface shows it. Values are what the file or the merged settings say, secrets as ***. */
|
|
15
|
+
export const SettingRowSchema = z.object({
|
|
16
|
+
id: z.string().describe('The setting, e.g. sandbox.memoryMb'),
|
|
17
|
+
key: z.array(z.string()),
|
|
18
|
+
label: z.string(),
|
|
19
|
+
category: z.string(),
|
|
20
|
+
/** A heading inside the category (Toolchains › Node.js). */
|
|
21
|
+
section: z.string().optional(),
|
|
22
|
+
field: FieldSchema,
|
|
23
|
+
/** In effect in this scope (this project: only what its file says). */
|
|
24
|
+
value: z.unknown(),
|
|
25
|
+
/** Written in this scope's file. */
|
|
26
|
+
set: z.boolean(),
|
|
27
|
+
/** Your own setting in effect (all projects), and whether your file sets it. */
|
|
28
|
+
yours: z.unknown(),
|
|
29
|
+
yoursSet: z.boolean(),
|
|
30
|
+
/** What this project's file says (undefined: not set there, or a project cannot set it). */
|
|
31
|
+
inProject: z.unknown().optional(),
|
|
32
|
+
/** The built-in default (your own settings only). */
|
|
33
|
+
default: z.unknown().optional(),
|
|
34
|
+
/** A project can only make this stricter than your own setting. */
|
|
35
|
+
locked: z.boolean(),
|
|
36
|
+
});
|
|
37
|
+
export const SettingsListSchema = z.object({
|
|
38
|
+
scope: ScopeSchema,
|
|
39
|
+
file: z.string().describe('The file this scope edits'),
|
|
40
|
+
exists: z.boolean(),
|
|
41
|
+
/** Your own settings: where the data folder is (it has its own flow; its setting is not listed). */
|
|
42
|
+
dataFolder: z.string().optional(),
|
|
43
|
+
categories: z.array(z.object({ id: z.string(), label: z.string(), description: z.string() })),
|
|
44
|
+
rows: z.array(SettingRowSchema),
|
|
45
|
+
});
|
|
46
|
+
export const listSettings = defineQuery({
|
|
47
|
+
id: 'settings.list',
|
|
48
|
+
title: 'Settings',
|
|
49
|
+
summary: 'every setting with its value, by category',
|
|
50
|
+
input: z.object({ scope: ScopeSchema.default('user') }),
|
|
51
|
+
output: SettingsListSchema,
|
|
52
|
+
cli: { name: 'config', action: 'list', json: true },
|
|
53
|
+
});
|
|
54
|
+
export const getSetting = defineQuery({
|
|
55
|
+
id: 'settings.get',
|
|
56
|
+
title: 'Get a setting',
|
|
57
|
+
summary: 'show one setting (secrets as ***)',
|
|
58
|
+
input: z.object({ key: KeySchema }),
|
|
59
|
+
output: z.object({ key: z.string(), value: z.unknown() }),
|
|
60
|
+
text: (o) => (typeof o.value === 'string' ? o.value : JSON.stringify(o.value, null, 2)),
|
|
61
|
+
surfaces: { except: { menu: 'Settings shows every value', web: 'the Settings page shows every value' } },
|
|
62
|
+
cli: { name: 'config', action: 'get', positional: ['key'] },
|
|
63
|
+
});
|
|
64
|
+
export const setSetting = defineOperation({
|
|
65
|
+
id: 'settings.set',
|
|
66
|
+
title: 'Change a setting',
|
|
67
|
+
summary: 'change one setting (text is read like the command line: true/on, numbers, JSON)',
|
|
68
|
+
input: z.object({
|
|
69
|
+
scope: ScopeSchema.default('user'),
|
|
70
|
+
key: KeySchema,
|
|
71
|
+
value: z.unknown().describe('The new value'),
|
|
72
|
+
}),
|
|
73
|
+
output: z.object({ key: z.string(), changed: z.boolean(), message: z.string() }),
|
|
74
|
+
text: (o) => o.message,
|
|
75
|
+
cli: { name: 'config', action: 'set', positional: ['key', 'value'] },
|
|
76
|
+
});
|
|
77
|
+
export const resetSetting = defineOperation({
|
|
78
|
+
id: 'settings.reset',
|
|
79
|
+
title: 'Reset a setting',
|
|
80
|
+
summary: 'put one setting back to its default (in a project file: remove it)',
|
|
81
|
+
input: z.object({ scope: ScopeSchema.default('user'), key: KeySchema }),
|
|
82
|
+
output: z.object({ key: z.string(), changed: z.boolean(), message: z.string() }),
|
|
83
|
+
text: (o) => o.message,
|
|
84
|
+
cli: { name: 'config', action: 'reset', positional: ['key'] },
|
|
85
|
+
});
|
|
86
|
+
/** The facts under a setting: its key, your value, the project's, the default, and the lock. */
|
|
87
|
+
function details(row, scope) {
|
|
88
|
+
const text = (v) => valueText(v, row.field, 40).text;
|
|
89
|
+
return [
|
|
90
|
+
'Setting ' + row.id,
|
|
91
|
+
'All projects ' + text(row.yours) + (row.yoursSet ? ' (your file)' : ' (built-in default)'),
|
|
92
|
+
'This project ' + (row.inProject === undefined ? 'not set' : text(row.inProject)),
|
|
93
|
+
...(scope === 'user' ? ['Default ' + text(row.default)] : []),
|
|
94
|
+
...(scope === 'project' && row.locked ? ['A project can only make this stricter than your own setting.'] : []),
|
|
95
|
+
];
|
|
96
|
+
}
|
|
97
|
+
function settingItem(row, scope) {
|
|
98
|
+
const shown = scope === 'project' && !row.set
|
|
99
|
+
? 'all projects: ' + valueText(row.yours, row.field, 40).text
|
|
100
|
+
: valueText(row.value, row.field).text;
|
|
101
|
+
const editable = row.field.kind === 'secret' ? '' : row.value;
|
|
102
|
+
return {
|
|
103
|
+
id: row.id,
|
|
104
|
+
label: row.label,
|
|
105
|
+
hint: shown,
|
|
106
|
+
...(row.set ? { tone: scope === 'project' ? 'accent' : 'ok', badges: [{ text: 'set', tone: 'accent' }] } : {}),
|
|
107
|
+
description: row.field.help,
|
|
108
|
+
group: row.section,
|
|
109
|
+
details: details(row, scope),
|
|
110
|
+
keywords: row.id,
|
|
111
|
+
cells: { setting: row.id, value: shown },
|
|
112
|
+
primary: action(setSetting, { scope, key: row.id }, {
|
|
113
|
+
label: 'Change',
|
|
114
|
+
verb: 'edit',
|
|
115
|
+
fields: [{ ...row.field, name: 'value', label: row.label }],
|
|
116
|
+
initial: { value: editable },
|
|
117
|
+
}),
|
|
118
|
+
actions: row.set
|
|
119
|
+
? [
|
|
120
|
+
action(resetSetting, { scope, key: row.id }, { label: scope === 'project' ? 'Remove' : 'Reset to default', verb: 'reset', key: 'r' }),
|
|
121
|
+
]
|
|
122
|
+
: [],
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
/** The Data folder row: where the saved data is; moving it has a flow of its own (menu; sandbox storage move). */
|
|
126
|
+
function dataFolderItem(folder) {
|
|
127
|
+
return {
|
|
128
|
+
id: '@data-folder',
|
|
129
|
+
label: 'Data folder',
|
|
130
|
+
hint: folder,
|
|
131
|
+
cells: { setting: 'storage.root', value: folder },
|
|
132
|
+
description: 'Where your tools, logins, history and logs are kept between sandboxes. Move it with the menu (Settings > Data folder) or sandbox storage move <folder>.',
|
|
133
|
+
primary: link({ kind: 'command', argv: ['storage'] }, 'Data folder', { verb: 'change' }),
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
/** The settings page of one scope: a section per category, each setting with its value and an edit action. */
|
|
137
|
+
export function settingsPage(o) {
|
|
138
|
+
const sections = o.categories.map((c) => ({
|
|
139
|
+
id: c.id,
|
|
140
|
+
title: c.label,
|
|
141
|
+
description: c.description,
|
|
142
|
+
columns: [
|
|
143
|
+
{ key: 'setting', label: 'SETTING' },
|
|
144
|
+
{ key: 'value', label: 'VALUE' },
|
|
145
|
+
],
|
|
146
|
+
columnsOn: 'cli',
|
|
147
|
+
items: [
|
|
148
|
+
...o.rows.filter((r) => r.category === c.id).map((r) => settingItem(r, o.scope)),
|
|
149
|
+
...(c.id === 'general' && o.dataFolder ? [dataFolderItem(o.dataFolder)] : []),
|
|
150
|
+
],
|
|
151
|
+
}));
|
|
152
|
+
return {
|
|
153
|
+
title: 'Settings',
|
|
154
|
+
notice: {
|
|
155
|
+
text: 'Editing ' +
|
|
156
|
+
o.file +
|
|
157
|
+
(o.exists ? '' : ' (created when you save)') +
|
|
158
|
+
(o.scope === 'project' ? ': only what a project may set; needs your approval at the next launch' : ''),
|
|
159
|
+
tone: o.scope === 'project' ? 'accent' : 'muted',
|
|
160
|
+
},
|
|
161
|
+
sections,
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
export const settingsView = defineView({
|
|
165
|
+
id: 'settings',
|
|
166
|
+
title: 'Settings',
|
|
167
|
+
summary: 'Every setting, for all projects or just this project, with its value, default and description.',
|
|
168
|
+
queries: { settings: listSettings },
|
|
169
|
+
operations: [setSetting, resetSetting],
|
|
170
|
+
tabs: {
|
|
171
|
+
param: 'scope',
|
|
172
|
+
choices: [
|
|
173
|
+
{ value: 'user', label: 'All projects' },
|
|
174
|
+
{ value: 'project', label: 'This project' },
|
|
175
|
+
],
|
|
176
|
+
},
|
|
177
|
+
inputs: (params) => ({ settings: { scope: params.scope } }),
|
|
178
|
+
build: ({ settings }) => settingsPage(settings),
|
|
179
|
+
});
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { type AppContext } from '../../context.js';
|
|
2
|
+
import { type SettingsFiles } from './settings-rows.js';
|
|
3
|
+
/** Your own settings file (the one --config names) and the project file of the current folder. */
|
|
4
|
+
export declare function settingsFiles(ctx: AppContext): SettingsFiles;
|
|
5
|
+
export declare const listSettingsRun: import("../../kernel/define.js").Implementation<import("../../kernel/define.js").QueryDef<import("zod").ZodObject<{
|
|
6
|
+
scope: import("zod").ZodDefault<import("zod").ZodEnum<{
|
|
7
|
+
project: "project";
|
|
8
|
+
user: "user";
|
|
9
|
+
}>>;
|
|
10
|
+
}, import("zod/v4/core").$strip>, import("zod").ZodObject<{
|
|
11
|
+
scope: import("zod").ZodEnum<{
|
|
12
|
+
project: "project";
|
|
13
|
+
user: "user";
|
|
14
|
+
}>;
|
|
15
|
+
file: import("zod").ZodString;
|
|
16
|
+
exists: import("zod").ZodBoolean;
|
|
17
|
+
dataFolder: import("zod").ZodOptional<import("zod").ZodString>;
|
|
18
|
+
categories: import("zod").ZodArray<import("zod").ZodObject<{
|
|
19
|
+
id: import("zod").ZodString;
|
|
20
|
+
label: import("zod").ZodString;
|
|
21
|
+
description: import("zod").ZodString;
|
|
22
|
+
}, import("zod/v4/core").$strip>>;
|
|
23
|
+
rows: import("zod").ZodArray<import("zod").ZodObject<{
|
|
24
|
+
id: import("zod").ZodString;
|
|
25
|
+
key: import("zod").ZodArray<import("zod").ZodString>;
|
|
26
|
+
label: import("zod").ZodString;
|
|
27
|
+
category: import("zod").ZodString;
|
|
28
|
+
section: import("zod").ZodOptional<import("zod").ZodString>;
|
|
29
|
+
field: import("zod").ZodType<import("../../kernel/fields.js").Field, unknown, import("zod/v4/core").$ZodTypeInternals<import("../../kernel/fields.js").Field, unknown>>;
|
|
30
|
+
value: import("zod").ZodUnknown;
|
|
31
|
+
set: import("zod").ZodBoolean;
|
|
32
|
+
yours: import("zod").ZodUnknown;
|
|
33
|
+
yoursSet: import("zod").ZodBoolean;
|
|
34
|
+
inProject: import("zod").ZodOptional<import("zod").ZodUnknown>;
|
|
35
|
+
default: import("zod").ZodOptional<import("zod").ZodUnknown>;
|
|
36
|
+
locked: import("zod").ZodBoolean;
|
|
37
|
+
}, import("zod/v4/core").$strip>>;
|
|
38
|
+
}, import("zod/v4/core").$strip>, "settings.list">, import("../../../cli/commands/context.js").Context>;
|
|
39
|
+
export declare const getSettingRun: import("../../kernel/define.js").Implementation<import("../../kernel/define.js").QueryDef<import("zod").ZodObject<{
|
|
40
|
+
key: import("zod").ZodString;
|
|
41
|
+
}, import("zod/v4/core").$strip>, import("zod").ZodObject<{
|
|
42
|
+
key: import("zod").ZodString;
|
|
43
|
+
value: import("zod").ZodUnknown;
|
|
44
|
+
}, import("zod/v4/core").$strip>, "settings.get">, import("../../../cli/commands/context.js").Context>;
|
|
45
|
+
export declare const setSettingRun: import("../../kernel/define.js").Implementation<import("../../kernel/define.js").OperationDef<import("zod").ZodObject<{
|
|
46
|
+
scope: import("zod").ZodDefault<import("zod").ZodEnum<{
|
|
47
|
+
project: "project";
|
|
48
|
+
user: "user";
|
|
49
|
+
}>>;
|
|
50
|
+
key: import("zod").ZodString;
|
|
51
|
+
value: import("zod").ZodUnknown;
|
|
52
|
+
}, import("zod/v4/core").$strip>, import("zod").ZodObject<{
|
|
53
|
+
key: import("zod").ZodString;
|
|
54
|
+
changed: import("zod").ZodBoolean;
|
|
55
|
+
message: import("zod").ZodString;
|
|
56
|
+
}, import("zod/v4/core").$strip>, "settings.set">, import("../../../cli/commands/context.js").Context>;
|
|
57
|
+
export declare const resetSettingRun: import("../../kernel/define.js").Implementation<import("../../kernel/define.js").OperationDef<import("zod").ZodObject<{
|
|
58
|
+
scope: import("zod").ZodDefault<import("zod").ZodEnum<{
|
|
59
|
+
project: "project";
|
|
60
|
+
user: "user";
|
|
61
|
+
}>>;
|
|
62
|
+
key: import("zod").ZodString;
|
|
63
|
+
}, import("zod/v4/core").$strip>, import("zod").ZodObject<{
|
|
64
|
+
key: import("zod").ZodString;
|
|
65
|
+
changed: import("zod").ZodBoolean;
|
|
66
|
+
message: import("zod").ZodString;
|
|
67
|
+
}, import("zod/v4/core").$strip>, "settings.reset">, import("../../../cli/commands/context.js").Context>;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
// The settings feature's work: the rows of a scope, and one setting read, changed or reset. Files are changed one
|
|
2
|
+
// setting at a time with comments kept, and nothing is written unless the whole file stays valid (settings-file.ts).
|
|
3
|
+
import _ from 'lodash';
|
|
4
|
+
import { redactSecrets } from '../../../core/schema/index.js';
|
|
5
|
+
import { fail } from '../../../core/util/index.js';
|
|
6
|
+
import { hereDir } from '../../../cli/commands/projects/here.js';
|
|
7
|
+
import { implement } from '../../context.js';
|
|
8
|
+
import { allowedText, valueFromText } from '../../kernel/index.js';
|
|
9
|
+
import { CATEGORIES } from './categories.def.js';
|
|
10
|
+
import { ConfigFile } from './settings-file.js';
|
|
11
|
+
import { findSetting, masked, settingRows } from './settings-rows.js';
|
|
12
|
+
import { getSetting, listSettings, resetSetting, setSetting } from './settings.def.js';
|
|
13
|
+
/** Your own settings file (the one --config names) and the project file of the current folder. */
|
|
14
|
+
export function settingsFiles(ctx) {
|
|
15
|
+
return { user: ConfigFile.user(ctx.loaded.configPath), project: ConfigFile.project(hereDir(ctx)) };
|
|
16
|
+
}
|
|
17
|
+
/** A typed or sent value as the setting reads it: text goes through the command line's rules (true/on, numbers ...). */
|
|
18
|
+
function valueFor(node, value) {
|
|
19
|
+
return typeof value === 'string' ? valueFromText(node, value) : value;
|
|
20
|
+
}
|
|
21
|
+
export const listSettingsRun = implement(listSettings, (ctx, input) => {
|
|
22
|
+
const files = settingsFiles(ctx);
|
|
23
|
+
const file = files[input.scope];
|
|
24
|
+
const rows = settingRows(files, input.scope).filter((r) => input.scope === 'project' || r.id !== 'storage.root');
|
|
25
|
+
return {
|
|
26
|
+
scope: input.scope,
|
|
27
|
+
file: file.file,
|
|
28
|
+
exists: file.exists,
|
|
29
|
+
...(input.scope === 'user' ? { dataFolder: ctx.storageRoot } : {}),
|
|
30
|
+
categories: CATEGORIES.filter((c) => rows.some((r) => r.category === c.id)).map((c) => ({
|
|
31
|
+
id: c.id,
|
|
32
|
+
label: c.label,
|
|
33
|
+
description: c.description,
|
|
34
|
+
})),
|
|
35
|
+
rows,
|
|
36
|
+
};
|
|
37
|
+
});
|
|
38
|
+
export const getSettingRun = implement(getSetting, (ctx, input) => {
|
|
39
|
+
const file = settingsFiles(ctx).user;
|
|
40
|
+
const { key } = findSetting(file, input.key);
|
|
41
|
+
// Secret values (an agent's API keys) are never shown.
|
|
42
|
+
return { key: input.key, value: _.get(redactSecrets(file.userConfig()), key) };
|
|
43
|
+
});
|
|
44
|
+
/** The file of a scope, and the setting a key names in it. */
|
|
45
|
+
function target(ctx, scope, name) {
|
|
46
|
+
const file = settingsFiles(ctx)[scope];
|
|
47
|
+
return { ...findSetting(file, name), file };
|
|
48
|
+
}
|
|
49
|
+
export const setSettingRun = implement(setSetting, (ctx, input) => {
|
|
50
|
+
const { key, node, file } = target(ctx, input.scope, input.key);
|
|
51
|
+
if (node.isSection)
|
|
52
|
+
fail('"' + input.key + '" is a group of settings.', 'Set one of them, e.g. ' + node.leaves(key)[0]?.key.join('.'));
|
|
53
|
+
const value = valueFor(node, input.value);
|
|
54
|
+
const problem = node.check(value);
|
|
55
|
+
if (problem !== true) {
|
|
56
|
+
const typed = typeof input.value === 'string' ? input.value : JSON.stringify(masked(key, input.value));
|
|
57
|
+
fail('"' + typed + '" does not work for ' + input.key + ': ' + problem, allowedText(node));
|
|
58
|
+
}
|
|
59
|
+
const outcome = file.set(key, value);
|
|
60
|
+
if (typeof outcome === 'object')
|
|
61
|
+
fail('Could not change ' + input.key + ': ' + outcome.problems.join('; '), 'Nothing was written.');
|
|
62
|
+
return {
|
|
63
|
+
key: input.key,
|
|
64
|
+
changed: outcome === 'saved',
|
|
65
|
+
message: input.key +
|
|
66
|
+
' is ' +
|
|
67
|
+
JSON.stringify(masked(key, value)) +
|
|
68
|
+
(outcome === 'unchanged' ? ' (it was already)' : '') +
|
|
69
|
+
'.',
|
|
70
|
+
};
|
|
71
|
+
});
|
|
72
|
+
export const resetSettingRun = implement(resetSetting, (ctx, input) => {
|
|
73
|
+
const { key, file } = target(ctx, input.scope, input.key);
|
|
74
|
+
const outcome = file.set(key, undefined);
|
|
75
|
+
if (typeof outcome === 'object')
|
|
76
|
+
fail('Could not reset ' + input.key + ': ' + outcome.problems.join('; '), 'Nothing was written.');
|
|
77
|
+
return {
|
|
78
|
+
key: input.key,
|
|
79
|
+
changed: outcome === 'saved',
|
|
80
|
+
message: file.isProject
|
|
81
|
+
? input.key + ' is not set in ' + file.file + ' any more.'
|
|
82
|
+
: input.key + ' is back to its default: ' + JSON.stringify(masked(key, file.defaultOf(key))) + '.',
|
|
83
|
+
};
|
|
84
|
+
});
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import type { z } from 'zod';
|
|
2
|
+
import type { OperationIO } from './io.js';
|
|
3
|
+
import type { Page } from './view.js';
|
|
4
|
+
export type SurfaceName = 'cli' | 'menu' | 'web';
|
|
5
|
+
export declare const SURFACE_NAMES: readonly SurfaceName[];
|
|
6
|
+
/** Where a definition is offered: everywhere, or everywhere but these surfaces (each with the reason). */
|
|
7
|
+
export type Surfaces = 'all' | {
|
|
8
|
+
readonly except: Readonly<Partial<Record<SurfaceName, string>>>;
|
|
9
|
+
};
|
|
10
|
+
/** The command groups of `sandbox --help` (and the menu's command list). */
|
|
11
|
+
export type CommandGroup = 'Agents' | 'Sessions' | 'Projects & accounts' | 'Data' | 'Web' | 'Health' | 'Advanced';
|
|
12
|
+
/** Lists filled in at run time (the menu's command form offers them). */
|
|
13
|
+
export type DynamicChoices = 'harnesses' | 'accounts' | 'sessions';
|
|
14
|
+
/** How one input field is spelled on the command line (the description comes from the schema's .describe()). */
|
|
15
|
+
export interface CliFlag {
|
|
16
|
+
readonly flag: `--${string}`;
|
|
17
|
+
readonly short?: `-${string}`;
|
|
18
|
+
/** The name --help shows; `flag` stays accepted as a hidden alias. */
|
|
19
|
+
readonly shownAs?: `--${string}`;
|
|
20
|
+
/** Placeholder in --help (name for --agent <name>). */
|
|
21
|
+
readonly value?: string;
|
|
22
|
+
readonly choices?: DynamicChoices | readonly string[];
|
|
23
|
+
readonly noMenu?: boolean;
|
|
24
|
+
readonly advanced?: boolean;
|
|
25
|
+
readonly label?: string;
|
|
26
|
+
}
|
|
27
|
+
/** The command line for a definition: a command of its own, or an action of an existing command (`config get`). */
|
|
28
|
+
export interface CliHint {
|
|
29
|
+
readonly name: string;
|
|
30
|
+
readonly action?: string;
|
|
31
|
+
/** Required for a command of its own. */
|
|
32
|
+
readonly group?: CommandGroup;
|
|
33
|
+
/** --help's one line (default: the definition's summary). */
|
|
34
|
+
readonly summary?: string;
|
|
35
|
+
/** Input fields given as positional arguments, in order (after the action, if any). */
|
|
36
|
+
readonly positional?: readonly string[];
|
|
37
|
+
readonly flags?: Readonly<Record<string, CliFlag | undefined>>;
|
|
38
|
+
/** The command takes -y/--yes, which answers its confirmations; the text is its --help line. */
|
|
39
|
+
readonly yes?: string;
|
|
40
|
+
/** Offers --json. */
|
|
41
|
+
readonly json?: boolean;
|
|
42
|
+
/** Shapes what --json prints (kept as the command printed it before the core); default: the output. */
|
|
43
|
+
shapeJson?(output: unknown): unknown;
|
|
44
|
+
readonly examples?: readonly string[];
|
|
45
|
+
}
|
|
46
|
+
/** A CliHint as written in a definition: field names checked against the input, the output typed. */
|
|
47
|
+
export interface TypedCliHint<I, O> extends Omit<CliHint, 'positional' | 'flags' | 'shapeJson'> {
|
|
48
|
+
readonly positional?: readonly (keyof I & string)[];
|
|
49
|
+
readonly flags?: {
|
|
50
|
+
readonly [K in keyof I]?: CliFlag;
|
|
51
|
+
};
|
|
52
|
+
shapeJson?(output: O): unknown;
|
|
53
|
+
}
|
|
54
|
+
interface Definition<Id extends string, I extends z.ZodType, O extends z.ZodType> {
|
|
55
|
+
readonly id: Id;
|
|
56
|
+
/** Menu row, web button or heading, CLI summary. */
|
|
57
|
+
readonly title: string;
|
|
58
|
+
readonly summary: string;
|
|
59
|
+
readonly input: I;
|
|
60
|
+
readonly output: O;
|
|
61
|
+
/** Default: every surface. */
|
|
62
|
+
readonly surfaces?: Surfaces;
|
|
63
|
+
readonly cli?: CliHint;
|
|
64
|
+
/** The output in one text: what an operation did, or a value a query read (CLI output, menu notice, web note). */
|
|
65
|
+
text?(output: z.output<O>): string;
|
|
66
|
+
}
|
|
67
|
+
/** What a definition is written as: its CLI hint typed against its own schemas. */
|
|
68
|
+
type Written<D extends Definition<string, z.ZodType, z.ZodType>> = Omit<D, 'kind' | 'cli'> & {
|
|
69
|
+
readonly cli?: TypedCliHint<z.input<D['input']>, z.output<D['output']>>;
|
|
70
|
+
};
|
|
71
|
+
export interface OperationDef<I extends z.ZodType = z.ZodType, O extends z.ZodType = z.ZodType, Id extends string = string> extends Definition<Id, I, O> {
|
|
72
|
+
readonly kind: 'operation';
|
|
73
|
+
/** Shown as dangerous (red); it asks for its own confirmation through io.confirm. */
|
|
74
|
+
readonly danger?: boolean;
|
|
75
|
+
}
|
|
76
|
+
export interface QueryDef<I extends z.ZodType = z.ZodType, O extends z.ZodType = z.ZodType, Id extends string = string> extends Definition<Id, I, O> {
|
|
77
|
+
readonly kind: 'query';
|
|
78
|
+
/** Read again this often while shown (the menu's status line and the web's subscriptions use the same rule). */
|
|
79
|
+
readonly live?: {
|
|
80
|
+
readonly everyMs: number;
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
export type AnyDefinition = OperationDef | QueryDef;
|
|
84
|
+
export type InputOf<D extends AnyDefinition> = z.output<D['input']>;
|
|
85
|
+
export type OutputOf<D extends AnyDefinition> = z.output<D['output']>;
|
|
86
|
+
export type QueryMap = Readonly<Record<string, QueryDef>>;
|
|
87
|
+
export type ViewData<Q extends QueryMap> = {
|
|
88
|
+
readonly [K in keyof Q]: z.output<Q[K]['output']>;
|
|
89
|
+
};
|
|
90
|
+
export type ViewInputs<Q extends QueryMap> = {
|
|
91
|
+
readonly [K in keyof Q]?: z.input<Q[K]['input']>;
|
|
92
|
+
};
|
|
93
|
+
/** The tabs of a view: which parameter they set, and its values. */
|
|
94
|
+
export interface ViewTabs<P> {
|
|
95
|
+
readonly param: keyof P & string;
|
|
96
|
+
readonly choices: readonly {
|
|
97
|
+
readonly value: string;
|
|
98
|
+
readonly label: string;
|
|
99
|
+
}[];
|
|
100
|
+
}
|
|
101
|
+
export interface ViewDef<Q extends QueryMap = QueryMap, P = Record<string, never>, Id extends string = string> {
|
|
102
|
+
readonly kind: 'view';
|
|
103
|
+
readonly id: Id;
|
|
104
|
+
readonly title: string;
|
|
105
|
+
readonly summary: string;
|
|
106
|
+
readonly queries: Q;
|
|
107
|
+
/** Every operation the page may offer (the parity check reads this). */
|
|
108
|
+
readonly operations: readonly OperationDef[];
|
|
109
|
+
/** A parameter switched with tabs above the page (Settings: all projects or this project), first choice default. */
|
|
110
|
+
readonly tabs?: ViewTabs<P>;
|
|
111
|
+
/** The input of each query for these view parameters (default: each query's defaults). */
|
|
112
|
+
inputs?(params: P): ViewInputs<Q>;
|
|
113
|
+
/** Pure: query results in, a Page out. */
|
|
114
|
+
build(data: ViewData<Q>, params: P): Page;
|
|
115
|
+
}
|
|
116
|
+
export declare function defineOperation<const Id extends string, I extends z.ZodType, O extends z.ZodType>(def: Written<OperationDef<I, O, Id>>): OperationDef<I, O, Id>;
|
|
117
|
+
export declare function defineQuery<const Id extends string, I extends z.ZodType, O extends z.ZodType>(def: Written<QueryDef<I, O, Id>>): QueryDef<I, O, Id>;
|
|
118
|
+
/** Any view, whatever its parameters (a list of views, a view looked up by id); call build with the right ones. */
|
|
119
|
+
export type AnyView = ViewDef<QueryMap, never>;
|
|
120
|
+
export declare function defineView<const Id extends string, Q extends QueryMap, P = Record<string, never>>(def: Omit<ViewDef<Q, P, Id>, 'kind'>): ViewDef<Q, P, Id>;
|
|
121
|
+
/** Why a definition is not on a surface, or undefined when it is. */
|
|
122
|
+
export declare function exemption(def: {
|
|
123
|
+
readonly surfaces?: Surfaces;
|
|
124
|
+
}, surface: SurfaceName): string | undefined;
|
|
125
|
+
export declare function onSurface(def: {
|
|
126
|
+
readonly surfaces?: Surfaces;
|
|
127
|
+
}, surface: SurfaceName): boolean;
|
|
128
|
+
/** A definition with its run function (Node side). `Ctx` is what the program gives every run (app/context.ts). */
|
|
129
|
+
export interface Implementation<D extends AnyDefinition = AnyDefinition, Ctx = unknown> {
|
|
130
|
+
readonly def: D;
|
|
131
|
+
run(ctx: Ctx, input: InputOf<D>, io: OperationIO): Promise<OutputOf<D>>;
|
|
132
|
+
}
|
|
133
|
+
/** Binds implement() to the program's context type once (app/context.ts), so features write implement(def, run). */
|
|
134
|
+
export declare function implementer<Ctx>(): <D extends AnyDefinition>(def: D, run: (ctx: Ctx, input: InputOf<D>, io: OperationIO) => Promise<OutputOf<D>> | OutputOf<D>) => Implementation<D, Ctx>;
|
|
135
|
+
/** The input as the definition reads it (defaults filled in); a value that does not fit says what is wrong. */
|
|
136
|
+
export declare function parseInput<D extends AnyDefinition>(def: D, input: unknown): InputOf<D>;
|
|
137
|
+
/** Runs an implementation the way every surface must: input checked before, output checked after. */
|
|
138
|
+
export declare function invoke<D extends AnyDefinition, Ctx>(impl: Implementation<D, Ctx>, ctx: Ctx, input: unknown, io: OperationIO): Promise<OutputOf<D>>;
|
|
139
|
+
/** The inputs a view's queries run with for these parameters (defaults filled in). */
|
|
140
|
+
export declare function viewInputs<Q extends QueryMap, P>(view: ViewDef<Q, P>, params: P): {
|
|
141
|
+
[K in keyof Q]: unknown;
|
|
142
|
+
};
|
|
143
|
+
export {};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { fail } from '../../core/util/errors.js';
|
|
2
|
+
import { issuesText } from './errors.js';
|
|
3
|
+
export const SURFACE_NAMES = ['cli', 'menu', 'web'];
|
|
4
|
+
export function defineOperation(def) {
|
|
5
|
+
return { ...def, cli: def.cli, kind: 'operation' };
|
|
6
|
+
}
|
|
7
|
+
export function defineQuery(def) {
|
|
8
|
+
return { ...def, cli: def.cli, kind: 'query' };
|
|
9
|
+
}
|
|
10
|
+
export function defineView(def) {
|
|
11
|
+
return { ...def, kind: 'view' };
|
|
12
|
+
}
|
|
13
|
+
/** Why a definition is not on a surface, or undefined when it is. */
|
|
14
|
+
export function exemption(def, surface) {
|
|
15
|
+
return def.surfaces === undefined || def.surfaces === 'all' ? undefined : def.surfaces.except[surface];
|
|
16
|
+
}
|
|
17
|
+
export function onSurface(def, surface) {
|
|
18
|
+
return exemption(def, surface) === undefined;
|
|
19
|
+
}
|
|
20
|
+
/** Binds implement() to the program's context type once (app/context.ts), so features write implement(def, run). */
|
|
21
|
+
export function implementer() {
|
|
22
|
+
return function implement(def, run) {
|
|
23
|
+
return { def, run: async (ctx, input, io) => run(ctx, input, io) };
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
/** The input as the definition reads it (defaults filled in); a value that does not fit says what is wrong. */
|
|
27
|
+
export function parseInput(def, input) {
|
|
28
|
+
const parsed = def.input.safeParse(input ?? {});
|
|
29
|
+
if (!parsed.success)
|
|
30
|
+
fail('That does not work for ' + def.title.toLowerCase() + ': ' + issuesText(parsed.error));
|
|
31
|
+
return parsed.data;
|
|
32
|
+
}
|
|
33
|
+
/** Runs an implementation the way every surface must: input checked before, output checked after. */
|
|
34
|
+
export async function invoke(impl, ctx, input, io) {
|
|
35
|
+
const output = await impl.run(ctx, parseInput(impl.def, input), io);
|
|
36
|
+
return impl.def.output.parse(output);
|
|
37
|
+
}
|
|
38
|
+
/** The inputs a view's queries run with for these parameters (defaults filled in). */
|
|
39
|
+
export function viewInputs(view, params) {
|
|
40
|
+
const given = view.inputs?.(params) ?? {};
|
|
41
|
+
return Object.fromEntries(Object.entries(view.queries).map(([name, query]) => [name, parseInput(query, given[name])]));
|
|
42
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare const ErrorKindSchema: z.ZodEnum<{
|
|
3
|
+
user: "user";
|
|
4
|
+
cancelled: "cancelled";
|
|
5
|
+
invalid: "invalid";
|
|
6
|
+
bug: "bug";
|
|
7
|
+
}>;
|
|
8
|
+
export type ErrorKind = z.output<typeof ErrorKindSchema>;
|
|
9
|
+
/** A failure as every surface shows it (and as the web receives it). */
|
|
10
|
+
export declare const WireErrorSchema: z.ZodObject<{
|
|
11
|
+
kind: z.ZodEnum<{
|
|
12
|
+
user: "user";
|
|
13
|
+
cancelled: "cancelled";
|
|
14
|
+
invalid: "invalid";
|
|
15
|
+
bug: "bug";
|
|
16
|
+
}>;
|
|
17
|
+
message: z.ZodString;
|
|
18
|
+
fix: z.ZodOptional<z.ZodString>;
|
|
19
|
+
}, z.core.$strict>;
|
|
20
|
+
export type WireError = z.output<typeof WireErrorSchema>;
|
|
21
|
+
/** The user said no to a question the operation needed: nothing changed. */
|
|
22
|
+
export declare class Cancelled extends Error {
|
|
23
|
+
constructor(message?: string);
|
|
24
|
+
}
|
|
25
|
+
/** Ends an operation because a question was declined. */
|
|
26
|
+
export declare function cancelled(message?: string): never;
|
|
27
|
+
/** What the user is told about a bug (its stack never leaves this PC). */
|
|
28
|
+
export declare const BUG_MESSAGE = "Something went wrong.";
|
|
29
|
+
/** Any thrown value as message + fix. */
|
|
30
|
+
export declare function toWireError(e: unknown): WireError;
|
|
31
|
+
/** The error to throw on the receiving side (the web client, a test). */
|
|
32
|
+
export declare function fromWireError(w: WireError): Error;
|
|
33
|
+
/** "key: problem; other: problem" for a value that did not fit its schema. */
|
|
34
|
+
export declare function issuesText(e: z.ZodError): string;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
// How a failure crosses a surface: a UserError (fail(message, fix)) stays a message and a fix everywhere, a declined
|
|
2
|
+
// question is "cancelled" (nothing changed), a value that does not fit a schema is "invalid", and anything else is a
|
|
3
|
+
// bug whose details stay on this PC.
|
|
4
|
+
import { z } from 'zod';
|
|
5
|
+
import { UserError } from '../../core/util/errors.js';
|
|
6
|
+
export const ErrorKindSchema = z.enum(['user', 'cancelled', 'invalid', 'bug']);
|
|
7
|
+
/** A failure as every surface shows it (and as the web receives it). */
|
|
8
|
+
export const WireErrorSchema = z.strictObject({
|
|
9
|
+
kind: ErrorKindSchema,
|
|
10
|
+
message: z.string().max(2000),
|
|
11
|
+
fix: z.string().max(2000).optional(),
|
|
12
|
+
});
|
|
13
|
+
/** The user said no to a question the operation needed: nothing changed. */
|
|
14
|
+
export class Cancelled extends Error {
|
|
15
|
+
constructor(message = 'Nothing changed.') {
|
|
16
|
+
super(message);
|
|
17
|
+
this.name = 'Cancelled';
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
/** Ends an operation because a question was declined. */
|
|
21
|
+
export function cancelled(message) {
|
|
22
|
+
throw new Cancelled(message);
|
|
23
|
+
}
|
|
24
|
+
/** What the user is told about a bug (its stack never leaves this PC). */
|
|
25
|
+
export const BUG_MESSAGE = 'Something went wrong.';
|
|
26
|
+
/** Any thrown value as message + fix. */
|
|
27
|
+
export function toWireError(e) {
|
|
28
|
+
if (e instanceof Cancelled)
|
|
29
|
+
return { kind: 'cancelled', message: e.message };
|
|
30
|
+
if (e instanceof UserError)
|
|
31
|
+
return { kind: 'user', message: e.message, ...(e.fix ? { fix: e.fix } : {}) };
|
|
32
|
+
if (e instanceof z.ZodError)
|
|
33
|
+
return { kind: 'invalid', message: issuesText(e) };
|
|
34
|
+
return { kind: 'bug', message: BUG_MESSAGE };
|
|
35
|
+
}
|
|
36
|
+
/** The error to throw on the receiving side (the web client, a test). */
|
|
37
|
+
export function fromWireError(w) {
|
|
38
|
+
if (w.kind === 'cancelled')
|
|
39
|
+
return new Cancelled(w.message);
|
|
40
|
+
return new UserError(w.message, w.fix);
|
|
41
|
+
}
|
|
42
|
+
/** "key: problem; other: problem" for a value that did not fit its schema. */
|
|
43
|
+
export function issuesText(e) {
|
|
44
|
+
return e.issues.map((i) => (i.path.length ? i.path.join('.') + ': ' : '') + i.message).join('; ');
|
|
45
|
+
}
|