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
|
@@ -6,6 +6,12 @@ export const VPN_LOGIN = '@vpn-login';
|
|
|
6
6
|
export function vpnLoginRow(ctx) {
|
|
7
7
|
const service = new VpnService(ctx);
|
|
8
8
|
const nord = service.provider === 'nordvpn';
|
|
9
|
+
if (service.provider === 'wireguard-file')
|
|
10
|
+
return {
|
|
11
|
+
label: 'VPN login',
|
|
12
|
+
hint: 'not needed',
|
|
13
|
+
description: 'A WireGuard file carries its own keys (vpn.configFile): there is no login to set.',
|
|
14
|
+
};
|
|
9
15
|
const state = service.loginState();
|
|
10
16
|
return {
|
|
11
17
|
label: nord ? 'Set NordVPN login…' : 'Set VPN login…',
|
|
@@ -25,6 +31,8 @@ export class VpnLoginFlow {
|
|
|
25
31
|
async run() {
|
|
26
32
|
const service = new VpnService(this.ctx);
|
|
27
33
|
const nord = service.provider === 'nordvpn';
|
|
34
|
+
if (service.provider === 'wireguard-file')
|
|
35
|
+
return 'A WireGuard file carries its own keys: no login is needed.';
|
|
28
36
|
const path = ['Settings', 'Network', 'VPN login'];
|
|
29
37
|
await this.app.message({
|
|
30
38
|
path,
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { type AnyDefinition } from '../../app/kernel/index.js';
|
|
2
|
+
import type { Handler } from '../commands/registry.js';
|
|
3
|
+
/** The command for a definition. */
|
|
4
|
+
export declare function definitionHandler(def: AnyDefinition): Handler;
|
|
5
|
+
/** The command a parsed command line runs when it is one of the shared core's, else undefined. */
|
|
6
|
+
export declare function operationHandler(command: string, positionals: readonly string[]): Handler | undefined;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
// Runs a definition as a command: its input from the command line, its questions on the terminal, and its output as
|
|
2
|
+
// --json, as the definition's one-line text, or as the page of the view that shows it. A declined question prints
|
|
3
|
+
// "Nothing changed." and exits 1, as the commands always have.
|
|
4
|
+
import { VIEWS } from '../../app/features/defs.js';
|
|
5
|
+
import { runDefinition } from '../../app/registry.js';
|
|
6
|
+
import { Cancelled } from '../../app/kernel/index.js';
|
|
7
|
+
import { printJson, printPage } from '../output/index.js';
|
|
8
|
+
import { cliInput, definitionFor } from './input.js';
|
|
9
|
+
import { cliIO } from './io-cli.js';
|
|
10
|
+
/** The view that shows only this query (its page is the command's text output). */
|
|
11
|
+
function viewOf(def) {
|
|
12
|
+
for (const view of VIEWS) {
|
|
13
|
+
const entries = Object.entries(view.queries);
|
|
14
|
+
if (entries.length === 1 && entries[0][1] === def)
|
|
15
|
+
return { view, name: entries[0][0] };
|
|
16
|
+
}
|
|
17
|
+
return undefined;
|
|
18
|
+
}
|
|
19
|
+
/** Prints what a definition returned, the way its command shows it. */
|
|
20
|
+
function printOutput(def, output, input) {
|
|
21
|
+
if (def.text) {
|
|
22
|
+
const text = def.text(output);
|
|
23
|
+
if (text)
|
|
24
|
+
console.log(text);
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
const shown = viewOf(def);
|
|
28
|
+
if (shown)
|
|
29
|
+
printPage(shown.view.build({ [shown.name]: output }, input));
|
|
30
|
+
else
|
|
31
|
+
console.log(JSON.stringify(output, null, 2));
|
|
32
|
+
}
|
|
33
|
+
/** The command for a definition. */
|
|
34
|
+
export function definitionHandler(def) {
|
|
35
|
+
return async (ctx) => {
|
|
36
|
+
const input = cliInput(def, ctx.options);
|
|
37
|
+
const { io, close } = cliIO(ctx.options);
|
|
38
|
+
try {
|
|
39
|
+
const output = await runDefinition(def.id, ctx, input, io);
|
|
40
|
+
close();
|
|
41
|
+
if (def.cli?.json && ctx.options.json) {
|
|
42
|
+
printJson(ctx, def.cli.shapeJson ? def.cli.shapeJson(output) : output);
|
|
43
|
+
return 0;
|
|
44
|
+
}
|
|
45
|
+
printOutput(def, output, def.input.parse(input));
|
|
46
|
+
return 0;
|
|
47
|
+
}
|
|
48
|
+
catch (e) {
|
|
49
|
+
close();
|
|
50
|
+
if (!(e instanceof Cancelled))
|
|
51
|
+
throw e;
|
|
52
|
+
console.log(e.message);
|
|
53
|
+
return 1;
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
/** The command a parsed command line runs when it is one of the shared core's, else undefined. */
|
|
58
|
+
export function operationHandler(command, positionals) {
|
|
59
|
+
const def = definitionFor(command, positionals);
|
|
60
|
+
return def ? definitionHandler(def) : undefined;
|
|
61
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { definitionHandler, operationHandler } from './handler.js';
|
|
2
|
+
export { cliInput, definitionFor } from './input.js';
|
|
3
|
+
export { cliIO } from './io-cli.js';
|
|
4
|
+
export { actionDefinitions, commandDefinitions, commandSpecOf, inputField, withActions, withOperationCommands, } from './spec.js';
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
// The command line of the shared core: commands from definitions, their input, their terminal IO and their output.
|
|
2
|
+
export { definitionHandler, operationHandler } from './handler.js';
|
|
3
|
+
export { cliInput, definitionFor } from './input.js';
|
|
4
|
+
export { cliIO } from './io-cli.js';
|
|
5
|
+
export { actionDefinitions, commandDefinitions, commandSpecOf, inputField, withActions, withOperationCommands, } from './spec.js';
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { AnyDefinition } from '../../app/kernel/index.js';
|
|
2
|
+
import type { CliOptions } from '../args.js';
|
|
3
|
+
/** The definition a command runs: its own command, or an action of a hand-written one (`config get`). */
|
|
4
|
+
export declare function definitionFor(command: string, positionals: readonly string[]): AnyDefinition | undefined;
|
|
5
|
+
/** The input a command line gives a definition (fields not on the line are left to the schema's defaults). */
|
|
6
|
+
export declare function cliInput(def: AnyDefinition, options: CliOptions): Record<string, unknown>;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// Which definition a parsed command line runs, and its input: positional arguments and flags mapped to input fields by
|
|
2
|
+
// the definition's CLI hint (zod then checks them like any other input).
|
|
3
|
+
import { DEFINITIONS } from '../../app/features/defs.js';
|
|
4
|
+
import { fail } from '../../core/util/index.js';
|
|
5
|
+
import { inputField } from './spec.js';
|
|
6
|
+
/** The definition a command runs: its own command, or an action of a hand-written one (`config get`). */
|
|
7
|
+
export function definitionFor(command, positionals) {
|
|
8
|
+
return DEFINITIONS.find((d) => d.cli?.name === command && (d.cli.action === undefined || d.cli.action === positionals[0]));
|
|
9
|
+
}
|
|
10
|
+
/** commander's attribute name for a long flag: --keep-old -> keepOld. */
|
|
11
|
+
function attribute(flag) {
|
|
12
|
+
return flag.replace(/^--/, '').replace(/-([a-z])/g, (_m, ch) => ch.toUpperCase());
|
|
13
|
+
}
|
|
14
|
+
/** The input a command line gives a definition (fields not on the line are left to the schema's defaults). */
|
|
15
|
+
export function cliInput(def, options) {
|
|
16
|
+
const hint = def.cli;
|
|
17
|
+
if (!hint)
|
|
18
|
+
return {};
|
|
19
|
+
const positionals = hint.action ? options.positionals.slice(1) : options.positionals;
|
|
20
|
+
const names = hint.positional ?? [];
|
|
21
|
+
const missing = names.slice(positionals.length).filter((name) => !inputField(def, name).optional);
|
|
22
|
+
if (missing.length)
|
|
23
|
+
fail('Missing ' + missing.join(' and ') + '.', 'Usage: sandbox ' + [hint.name, hint.action, ...names.map((n) => '<' + n + '>')].filter(Boolean).join(' '));
|
|
24
|
+
const input = {};
|
|
25
|
+
names.forEach((name, i) => {
|
|
26
|
+
if (positionals[i] !== undefined)
|
|
27
|
+
input[name] = positionals[i];
|
|
28
|
+
});
|
|
29
|
+
for (const [name, flag] of Object.entries(hint.flags ?? {})) {
|
|
30
|
+
if (!flag)
|
|
31
|
+
continue;
|
|
32
|
+
const value = (flag.shownAs ? options.raw[attribute(flag.shownAs)] : undefined) ?? options.raw[attribute(flag.flag)];
|
|
33
|
+
if (value !== undefined)
|
|
34
|
+
input[name] = value;
|
|
35
|
+
}
|
|
36
|
+
return input;
|
|
37
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { OperationIO } from '../../app/kernel/index.js';
|
|
2
|
+
import type { CliOptions } from '../args.js';
|
|
3
|
+
/** An OperationIO for one command; close() removes a progress line still shown. */
|
|
4
|
+
export declare function cliIO(options: CliOptions): {
|
|
5
|
+
io: OperationIO;
|
|
6
|
+
close: () => void;
|
|
7
|
+
};
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { ioFromAsker } from '../../app/kernel/index.js';
|
|
2
|
+
import { askChoice, askChoices, askName, askRequired, askSecret, askTyped } from '../../core/prompt.js';
|
|
3
|
+
import { fail } from '../../core/util/index.js';
|
|
4
|
+
import { c, ProgressLine } from '../output/index.js';
|
|
5
|
+
/** What to do instead when there is no terminal to ask in. */
|
|
6
|
+
const NO_TERMINAL_FIX = 'Run it in a terminal, or give the value on the command line.';
|
|
7
|
+
const PAINT = {
|
|
8
|
+
ok: c.green,
|
|
9
|
+
warn: c.yellow,
|
|
10
|
+
danger: c.red,
|
|
11
|
+
muted: c.dim,
|
|
12
|
+
accent: c.bold,
|
|
13
|
+
};
|
|
14
|
+
/** The question in one line, as a prompt says it: its lines, then the question itself. */
|
|
15
|
+
function promptText(q) {
|
|
16
|
+
return [...(q.lines ?? []), q.title].join(' ');
|
|
17
|
+
}
|
|
18
|
+
function interactive() {
|
|
19
|
+
return Boolean(process.stdin.isTTY && process.stdout.isTTY);
|
|
20
|
+
}
|
|
21
|
+
async function ask(q, options) {
|
|
22
|
+
if ('problem' in q && q.problem)
|
|
23
|
+
console.log(c.yellow(q.problem));
|
|
24
|
+
switch (q.kind) {
|
|
25
|
+
case 'confirm': {
|
|
26
|
+
if (q.implied || options.yes)
|
|
27
|
+
return true;
|
|
28
|
+
if (!interactive())
|
|
29
|
+
fail(q.noTerminal?.message ?? 'Cannot ask here (no terminal).', q.noTerminal?.fix ?? 'Add --yes to answer yes.');
|
|
30
|
+
if (q.typed)
|
|
31
|
+
return askTyped(promptText(q), q.typed);
|
|
32
|
+
return askRequired(promptText(q), q.noTerminal?.fix);
|
|
33
|
+
}
|
|
34
|
+
case 'choose':
|
|
35
|
+
return askChoice(promptText(q), q.choices.map((ch) => ({ name: ch.label, value: ch.value, description: ch.description })), NO_TERMINAL_FIX);
|
|
36
|
+
case 'checklist':
|
|
37
|
+
return askChoices(promptText(q), q.choices.map((ch) => ({ name: ch.label, value: ch.value, description: ch.description })), NO_TERMINAL_FIX);
|
|
38
|
+
case 'secret':
|
|
39
|
+
return askSecret(promptText(q), NO_TERMINAL_FIX);
|
|
40
|
+
case 'text':
|
|
41
|
+
case 'path': {
|
|
42
|
+
const answer = await askName(promptText(q), NO_TERMINAL_FIX);
|
|
43
|
+
return answer === '' && q.kind === 'text' && !q.allowEmpty ? undefined : answer;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
/** An OperationIO for one command; close() removes a progress line still shown. */
|
|
48
|
+
export function cliIO(options) {
|
|
49
|
+
const progress = new ProgressLine();
|
|
50
|
+
const asker = async (q) => {
|
|
51
|
+
progress.stop();
|
|
52
|
+
return (await ask(q, options));
|
|
53
|
+
};
|
|
54
|
+
const io = ioFromAsker(asker, {
|
|
55
|
+
progress: (text) => progress.show(text),
|
|
56
|
+
log: (text, tone) => {
|
|
57
|
+
progress.stop();
|
|
58
|
+
console.log(tone ? PAINT[tone](text) : text);
|
|
59
|
+
},
|
|
60
|
+
});
|
|
61
|
+
return { io, close: () => progress.stop() };
|
|
62
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type AnyDefinition, type Field } from '../../app/kernel/index.js';
|
|
2
|
+
import type { CommandSpec } from '../manifest.js';
|
|
3
|
+
/** The definitions that are a command of their own. */
|
|
4
|
+
export declare function commandDefinitions(): AnyDefinition[];
|
|
5
|
+
/** The definitions that are an action of a hand-written command. */
|
|
6
|
+
export declare function actionDefinitions(): AnyDefinition[];
|
|
7
|
+
/** The Field of one input field of a definition. */
|
|
8
|
+
export declare function inputField(def: AnyDefinition, name: string): Field;
|
|
9
|
+
/** The manifest command of a definition that is a command of its own. */
|
|
10
|
+
export declare function commandSpecOf(def: AnyDefinition): CommandSpec;
|
|
11
|
+
/**
|
|
12
|
+
* A hand-written command with the actions the definitions add (`config reset`): the action is one of the first
|
|
13
|
+
* argument's choices, each later argument is asked for it in the menu's command form, and --json is offered when an
|
|
14
|
+
* action prints JSON.
|
|
15
|
+
*/
|
|
16
|
+
export declare function withActions(spec: CommandSpec, defs?: readonly AnyDefinition[]): CommandSpec;
|
|
17
|
+
/** Every command the definitions add, and the hand-written ones with their added actions. */
|
|
18
|
+
export declare function withOperationCommands(handWritten: readonly CommandSpec[]): CommandSpec[];
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
// The command line of the shared core's definitions: each definition with a CLI hint becomes a manifest command (its
|
|
2
|
+
// options and arguments read from the input schema, their help from .describe()), or an action of an existing command
|
|
3
|
+
// (`config get`). manifest.ts adds these to the hand-written commands, so --help, the parser and the menu's command
|
|
4
|
+
// list treat them like any other command.
|
|
5
|
+
import { DEFINITIONS } from '../../app/features/defs.js';
|
|
6
|
+
import { fieldOf, SchemaNode } from '../../app/kernel/index.js';
|
|
7
|
+
/** The definitions that are a command of their own. */
|
|
8
|
+
export function commandDefinitions() {
|
|
9
|
+
return DEFINITIONS.filter((d) => d.cli && !d.cli.action);
|
|
10
|
+
}
|
|
11
|
+
/** The definitions that are an action of a hand-written command. */
|
|
12
|
+
export function actionDefinitions() {
|
|
13
|
+
return DEFINITIONS.filter((d) => d.cli?.action);
|
|
14
|
+
}
|
|
15
|
+
/** The Field of one input field of a definition. */
|
|
16
|
+
export function inputField(def, name) {
|
|
17
|
+
const node = new SchemaNode(def.input).child(name);
|
|
18
|
+
if (!node)
|
|
19
|
+
throw new Error(def.id + ': the CLI hint names "' + name + '", which is not in its input');
|
|
20
|
+
return fieldOf(node, [name]);
|
|
21
|
+
}
|
|
22
|
+
const OPTION_TYPES = {
|
|
23
|
+
boolean: 'boolean',
|
|
24
|
+
number: 'number',
|
|
25
|
+
list: 'list',
|
|
26
|
+
};
|
|
27
|
+
function stringChoices(field) {
|
|
28
|
+
const values = field.choices?.map((c) => c.value).filter((v) => typeof v === 'string');
|
|
29
|
+
return values?.length ? values : undefined;
|
|
30
|
+
}
|
|
31
|
+
function optionSpec(def, name, flag) {
|
|
32
|
+
const field = inputField(def, name);
|
|
33
|
+
const type = OPTION_TYPES[field.kind] ?? 'string';
|
|
34
|
+
const choices = flag.choices ? (typeof flag.choices === 'string' ? flag.choices : [...flag.choices]) : undefined;
|
|
35
|
+
const fixed = choices ?? stringChoices(field);
|
|
36
|
+
const fallback = field.default;
|
|
37
|
+
return {
|
|
38
|
+
flag: flag.flag,
|
|
39
|
+
type,
|
|
40
|
+
description: field.help ?? '',
|
|
41
|
+
...(flag.short ? { short: flag.short } : {}),
|
|
42
|
+
...(flag.shownAs ? { shownAs: flag.shownAs } : {}),
|
|
43
|
+
...(type === 'boolean' ? {} : { value: flag.value ?? name }),
|
|
44
|
+
...(flag.label ? { label: flag.label } : {}),
|
|
45
|
+
...(fixed ? { choices: fixed } : {}),
|
|
46
|
+
...(type !== 'boolean' && (typeof fallback === 'string' || typeof fallback === 'number')
|
|
47
|
+
? { default: fallback }
|
|
48
|
+
: {}),
|
|
49
|
+
...(flag.noMenu ? { noMenu: true } : {}),
|
|
50
|
+
...(flag.advanced ? { advanced: true } : {}),
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
function argSpec(def, name) {
|
|
54
|
+
const field = inputField(def, name);
|
|
55
|
+
const choices = stringChoices(field);
|
|
56
|
+
return {
|
|
57
|
+
name,
|
|
58
|
+
description: field.help ?? '',
|
|
59
|
+
required: !field.optional,
|
|
60
|
+
...(choices ? { choices } : {}),
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
/** The manifest command of a definition that is a command of its own. */
|
|
64
|
+
export function commandSpecOf(def) {
|
|
65
|
+
const hint = def.cli;
|
|
66
|
+
if (!hint?.group)
|
|
67
|
+
throw new Error(def.id + ': a CLI command of its own needs a group');
|
|
68
|
+
return {
|
|
69
|
+
name: hint.name,
|
|
70
|
+
summary: hint.summary ?? def.summary,
|
|
71
|
+
group: hint.group,
|
|
72
|
+
args: (hint.positional ?? []).map((name) => argSpec(def, name)),
|
|
73
|
+
options: [
|
|
74
|
+
...Object.entries(hint.flags ?? {}).flatMap(([name, flag]) => (flag ? [optionSpec(def, name, flag)] : [])),
|
|
75
|
+
...(hint.yes
|
|
76
|
+
? [{ flag: '--yes', short: '-y', type: 'boolean', description: hint.yes, noMenu: true }]
|
|
77
|
+
: []),
|
|
78
|
+
],
|
|
79
|
+
...(hint.json ? { json: true } : {}),
|
|
80
|
+
...(hint.examples ? { examples: [...hint.examples] } : {}),
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* A hand-written command with the actions the definitions add (`config reset`): the action is one of the first
|
|
85
|
+
* argument's choices, each later argument is asked for it in the menu's command form, and --json is offered when an
|
|
86
|
+
* action prints JSON.
|
|
87
|
+
*/
|
|
88
|
+
export function withActions(spec, defs = actionDefinitions()) {
|
|
89
|
+
const mine = defs.filter((d) => d.cli?.name === spec.name);
|
|
90
|
+
if (!mine.length || !spec.args.length)
|
|
91
|
+
return spec;
|
|
92
|
+
const [first, ...rest] = spec.args;
|
|
93
|
+
const actions = mine.map((d) => d.cli.action);
|
|
94
|
+
const choices = Array.isArray(first.choices) ? [...new Set([...first.choices, ...actions])] : first.choices;
|
|
95
|
+
const asked = (arg, position) => {
|
|
96
|
+
const users = mine.filter((d) => (d.cli?.positional?.length ?? 0) > position).map((d) => d.cli.action);
|
|
97
|
+
if (!users.length || arg.when === undefined)
|
|
98
|
+
return arg;
|
|
99
|
+
const when = Array.isArray(arg.when) ? arg.when : [arg.when];
|
|
100
|
+
return { ...arg, when: [...new Set([...when, ...users])] };
|
|
101
|
+
};
|
|
102
|
+
const json = spec.json || mine.some((d) => d.cli?.json) ? { json: true } : {};
|
|
103
|
+
return { ...spec, ...json, args: [{ ...first, choices }, ...rest.map(asked)] };
|
|
104
|
+
}
|
|
105
|
+
/** Every command the definitions add, and the hand-written ones with their added actions. */
|
|
106
|
+
export function withOperationCommands(handWritten) {
|
|
107
|
+
return [...handWritten.map((spec) => withActions(spec)), ...commandDefinitions().map(commandSpecOf)];
|
|
108
|
+
}
|
|
@@ -14,8 +14,8 @@ export declare function stripAnsi(text: string): string;
|
|
|
14
14
|
export declare function shorten(text: string, max: number): string;
|
|
15
15
|
/** Cuts the middle out of a long path or id so both ends stay readable. */
|
|
16
16
|
export declare function shortenMiddle(text: string, max: number): string;
|
|
17
|
-
/**
|
|
18
|
-
export
|
|
17
|
+
/** "3 min ago" for the tables (the kernel's, so every surface says it the same way). */
|
|
18
|
+
export { ago } from '../../app/kernel/index.js';
|
|
19
19
|
/** Width to lay text out in (terminal columns, 80 when unknown, never absurdly small). */
|
|
20
20
|
export declare function termWidth(): number;
|
|
21
21
|
/** Each menu page starts on a clean screen (answered prompts would otherwise pile up above it). */
|
|
@@ -34,17 +34,8 @@ export function shortenMiddle(text, max) {
|
|
|
34
34
|
const head = Math.ceil(keep / 2);
|
|
35
35
|
return text.slice(0, head) + '…' + text.slice(text.length - (keep - head));
|
|
36
36
|
}
|
|
37
|
-
/**
|
|
38
|
-
export
|
|
39
|
-
const secs = Math.max(0, Math.round((now - new Date(then).getTime()) / 1000));
|
|
40
|
-
if (secs < 45)
|
|
41
|
-
return 'just now';
|
|
42
|
-
if (secs < 3600)
|
|
43
|
-
return Math.round(secs / 60) + ' min ago';
|
|
44
|
-
if (secs < 86400)
|
|
45
|
-
return Math.round(secs / 3600) + ' h ago';
|
|
46
|
-
return Math.round(secs / 86400) + ' d ago';
|
|
47
|
-
}
|
|
37
|
+
/** "3 min ago" for the tables (the kernel's, so every surface says it the same way). */
|
|
38
|
+
export { ago } from '../../app/kernel/index.js';
|
|
48
39
|
/** Width to lay text out in (terminal columns, 80 when unknown, never absurdly small). */
|
|
49
40
|
export function termWidth() {
|
|
50
41
|
return Math.max(40, process.stdout.columns ?? 80);
|
package/dist/cli/output/index.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type { Context } from '../commands/context.js';
|
|
2
|
+
/** Rows as aligned columns (the last column is not padded). */
|
|
3
|
+
export declare function tableLines(rows: readonly (readonly string[])[]): string[];
|
|
2
4
|
/** Prints rows as aligned columns (the last column is not padded). */
|
|
3
|
-
export declare function table(rows: string[][]): void;
|
|
5
|
+
export declare function table(rows: readonly (readonly string[])[]): void;
|
|
4
6
|
/** Prints `value` as JSON when --json was given; returns whether it did. */
|
|
5
7
|
export declare function printJson(ctx: Context, value: unknown): boolean;
|
|
6
8
|
/** A dim "Next: ..." line after a command: the usual thing to do now. */
|
package/dist/cli/output/print.js
CHANGED
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
import _ from 'lodash';
|
|
2
2
|
import { scrubSecrets } from '../../core/schema/index.js';
|
|
3
3
|
import { c } from './colors.js';
|
|
4
|
+
/** Rows as aligned columns (the last column is not padded). */
|
|
5
|
+
export function tableLines(rows) {
|
|
6
|
+
const widths = _.range(_.max(rows.map((r) => r.length)) ?? 0).map((i) => _.max(rows.map((r) => (r[i] ?? '').length)) ?? 0);
|
|
7
|
+
return rows.map((row) => row.map((cell, i) => (i === row.length - 1 ? cell : _.padEnd(cell, widths[i] + 2))).join(''));
|
|
8
|
+
}
|
|
4
9
|
/** Prints rows as aligned columns (the last column is not padded). */
|
|
5
10
|
export function table(rows) {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
console.log(row.map((cell, i) => (i === row.length - 1 ? cell : _.padEnd(cell, widths[i] + 2))).join(''));
|
|
11
|
+
for (const line of tableLines(rows))
|
|
12
|
+
console.log(line);
|
|
9
13
|
}
|
|
10
14
|
/** Prints `value` as JSON when --json was given; returns whether it did. */
|
|
11
15
|
export function printJson(ctx, value) {
|
|
@@ -22,3 +22,18 @@ export declare function follow<T>(show: () => Progressing, work: () => Promise<T
|
|
|
22
22
|
* (waiting on the sandbox); for long synchronous work (measuring folders) the static line is what you see.
|
|
23
23
|
*/
|
|
24
24
|
export declare function working<T>(message: string | (() => string), work: () => Promise<T> | T, enabled?: boolean): Promise<T>;
|
|
25
|
+
/**
|
|
26
|
+
* A progress line that follows an operation (its io.progress): on a terminal one line redrawn in place until stop();
|
|
27
|
+
* without one, each new text once as "text...". Prompts and log lines call stop() first.
|
|
28
|
+
*/
|
|
29
|
+
export declare class ProgressLine {
|
|
30
|
+
private text;
|
|
31
|
+
private timer;
|
|
32
|
+
private frame;
|
|
33
|
+
private start;
|
|
34
|
+
private readonly animate;
|
|
35
|
+
show(text: string): void;
|
|
36
|
+
private draw;
|
|
37
|
+
/** Removes the line (the next show() starts it again). */
|
|
38
|
+
stop(): void;
|
|
39
|
+
}
|
|
@@ -122,3 +122,47 @@ export async function working(message, work, enabled = true) {
|
|
|
122
122
|
err.write('\r\x1b[2K');
|
|
123
123
|
}
|
|
124
124
|
}
|
|
125
|
+
/**
|
|
126
|
+
* A progress line that follows an operation (its io.progress): on a terminal one line redrawn in place until stop();
|
|
127
|
+
* without one, each new text once as "text...". Prompts and log lines call stop() first.
|
|
128
|
+
*/
|
|
129
|
+
export class ProgressLine {
|
|
130
|
+
text = '';
|
|
131
|
+
timer;
|
|
132
|
+
frame = 0;
|
|
133
|
+
start = 0;
|
|
134
|
+
animate = canAnimate(process.env, Boolean(process.stderr.isTTY));
|
|
135
|
+
show(text) {
|
|
136
|
+
if (text === this.text && (this.timer || !this.animate))
|
|
137
|
+
return;
|
|
138
|
+
this.text = text;
|
|
139
|
+
if (!this.animate) {
|
|
140
|
+
process.stderr.write(text + '...\n');
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
if (!this.timer) {
|
|
144
|
+
this.start = Date.now();
|
|
145
|
+
this.timer = setInterval(() => this.draw(), 120);
|
|
146
|
+
}
|
|
147
|
+
this.draw();
|
|
148
|
+
}
|
|
149
|
+
draw() {
|
|
150
|
+
const colour = colorEnabled(process.env, true);
|
|
151
|
+
process.stderr.write('\r\x1b[2K' +
|
|
152
|
+
(colour ? '\x1b[36m' : '') +
|
|
153
|
+
FRAMES[this.frame++ % FRAMES.length] +
|
|
154
|
+
(colour ? '\x1b[0m' : '') +
|
|
155
|
+
' ' +
|
|
156
|
+
shorten(this.text, termWidth() - 14) +
|
|
157
|
+
(Date.now() - this.start > 3000 ? ' (' + elapsed(Date.now() - this.start) + ')' : ''));
|
|
158
|
+
}
|
|
159
|
+
/** Removes the line (the next show() starts it again). */
|
|
160
|
+
stop() {
|
|
161
|
+
if (this.timer) {
|
|
162
|
+
clearInterval(this.timer);
|
|
163
|
+
this.timer = undefined;
|
|
164
|
+
process.stderr.write('\r\x1b[2K');
|
|
165
|
+
}
|
|
166
|
+
this.text = '';
|
|
167
|
+
}
|
|
168
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { Page } from '../../app/kernel/index.js';
|
|
2
|
+
/** The page as lines of text (text that came from the sandbox was made safe by the feature; this makes sure). */
|
|
3
|
+
export declare function pageLines(page: Page): string[];
|
|
4
|
+
export declare function printPage(page: Page): void;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { pageHasContent } from '../../app/kernel/index.js';
|
|
2
|
+
import { safeText } from '../../core/util/index.js';
|
|
3
|
+
import { c } from './colors.js';
|
|
4
|
+
import { tableLines } from './print.js';
|
|
5
|
+
const PAINT = {
|
|
6
|
+
ok: (t) => t,
|
|
7
|
+
warn: c.yellow,
|
|
8
|
+
danger: c.red,
|
|
9
|
+
muted: c.dim,
|
|
10
|
+
accent: (t) => t,
|
|
11
|
+
};
|
|
12
|
+
const forCli = (n) => n.only === undefined || n.only === 'cli';
|
|
13
|
+
function itemLine(item) {
|
|
14
|
+
const label = item.tone ? PAINT[item.tone](item.label) : item.details?.length ? c.bold(item.label) : item.label;
|
|
15
|
+
return (item.marked ? '* ' : ' ') + label + (item.hint ? ' ' + item.hint : '');
|
|
16
|
+
}
|
|
17
|
+
function sectionLines(section) {
|
|
18
|
+
const items = section.items ?? [];
|
|
19
|
+
const lines = [];
|
|
20
|
+
if (section.title)
|
|
21
|
+
lines.push(c.bold(section.title) + (section.summary ? ' ' + section.summary : ''));
|
|
22
|
+
if (section.facts?.length)
|
|
23
|
+
lines.push(...tableLines(section.facts.map((f) => [f.label, f.value])));
|
|
24
|
+
if (section.columns && items.length) {
|
|
25
|
+
const columns = section.columns;
|
|
26
|
+
lines.push(...tableLines([
|
|
27
|
+
columns.map((col) => col.label),
|
|
28
|
+
...items.map((i) => columns.map((col) => i.cells?.[col.key] ?? '')),
|
|
29
|
+
]));
|
|
30
|
+
}
|
|
31
|
+
else
|
|
32
|
+
for (const item of items) {
|
|
33
|
+
lines.push(itemLine(item));
|
|
34
|
+
for (const detail of item.details ?? [])
|
|
35
|
+
lines.push(' ' + detail);
|
|
36
|
+
}
|
|
37
|
+
for (const note of (section.notes ?? []).filter(forCli))
|
|
38
|
+
lines.push(note.tone ? PAINT[note.tone](note.text) : note.text);
|
|
39
|
+
return lines;
|
|
40
|
+
}
|
|
41
|
+
/** The page as lines of text (text that came from the sandbox was made safe by the feature; this makes sure). */
|
|
42
|
+
export function pageLines(page) {
|
|
43
|
+
const out = [];
|
|
44
|
+
if (page.notice)
|
|
45
|
+
out.push(c.bold(page.notice.text));
|
|
46
|
+
if (!pageHasContent(page) && page.empty) {
|
|
47
|
+
out.push(page.empty.cliText ?? page.empty.text);
|
|
48
|
+
return out.map(safeText);
|
|
49
|
+
}
|
|
50
|
+
for (const section of page.sections) {
|
|
51
|
+
const lines = sectionLines(section);
|
|
52
|
+
if (!lines.length)
|
|
53
|
+
continue;
|
|
54
|
+
if (section.title && out.length)
|
|
55
|
+
out.push('');
|
|
56
|
+
out.push(...lines);
|
|
57
|
+
}
|
|
58
|
+
return out.map(safeText);
|
|
59
|
+
}
|
|
60
|
+
export function printPage(page) {
|
|
61
|
+
for (const line of pageLines(page))
|
|
62
|
+
console.log(line);
|
|
63
|
+
}
|
|
@@ -15,6 +15,8 @@ export declare class AgentCommandsService {
|
|
|
15
15
|
/** Agent commands change this PC's PATH, so they are set up from the PC, not inside the sandbox. */
|
|
16
16
|
assertOnPc(): void;
|
|
17
17
|
status(): AgentCommandsStatus;
|
|
18
|
+
/** status() that does not block the program (the menu asks while it stays responsive). */
|
|
19
|
+
statusAsync(): Promise<AgentCommandsStatus>;
|
|
18
20
|
/** Writes agentCommands.enabled to your config file, then brings this PC in line with it. */
|
|
19
21
|
setEnabled(on: boolean): Reconciled | null;
|
|
20
22
|
/** Brings this PC in line with agentCommands. Null inside a sandbox (nothing to change there). */
|
|
@@ -3,10 +3,10 @@ import fs from 'node:fs';
|
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
import { loadConfig, userConfigPath } from '../../core/config/index.js';
|
|
5
5
|
import { fail } from '../../core/util/index.js';
|
|
6
|
-
import { agentCommands, commandsDir, reconcileAgentCommands, } from '../../host/agent-commands/index.js';
|
|
6
|
+
import { agentCommands, agentCommandsAsync, commandsDir, reconcileAgentCommands, } from '../../host/agent-commands/index.js';
|
|
7
7
|
import { insideSandbox } from '../../host/sandbox/index.js';
|
|
8
8
|
import { writeFileAtomic } from '../../shared/io/index.js';
|
|
9
|
-
import { editConfigText } from '
|
|
9
|
+
import { editConfigText } from '../../app/features/settings/index.js';
|
|
10
10
|
export class AgentCommandsService {
|
|
11
11
|
ctx;
|
|
12
12
|
constructor(ctx) {
|
|
@@ -25,6 +25,15 @@ export class AgentCommandsService {
|
|
|
25
25
|
found: agentCommands(config, this.ctx.storageRoot),
|
|
26
26
|
};
|
|
27
27
|
}
|
|
28
|
+
/** status() that does not block the program (the menu asks while it stays responsive). */
|
|
29
|
+
async statusAsync() {
|
|
30
|
+
const { config } = this.ctx.loaded;
|
|
31
|
+
return {
|
|
32
|
+
enabled: config.agentCommands.enabled,
|
|
33
|
+
dir: commandsDir(this.ctx.storageRoot),
|
|
34
|
+
found: await agentCommandsAsync(config, this.ctx.storageRoot),
|
|
35
|
+
};
|
|
36
|
+
}
|
|
28
37
|
/** Writes agentCommands.enabled to your config file, then brings this PC in line with it. */
|
|
29
38
|
setEnabled(on) {
|
|
30
39
|
const file = this.ctx.loaded.configPath ?? userConfigPath();
|
|
@@ -3,6 +3,7 @@ import fs from 'node:fs';
|
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
import _ from 'lodash';
|
|
5
5
|
import { assertNoLinks, fail, safeText } from '../../core/util/index.js';
|
|
6
|
+
import { hostDataFolder, hostDataRoot } from '../../host/storage/index.js';
|
|
6
7
|
const LOG_NAME = /^(guest|daemon|bootstrap)-.*\.log$/;
|
|
7
8
|
/** Only the end of a log is read: the sandbox writes it. */
|
|
8
9
|
const FIRST_READ_BYTES = 64 * 1024;
|
|
@@ -13,8 +14,8 @@ export class LogsService {
|
|
|
13
14
|
this.ctx = ctx;
|
|
14
15
|
}
|
|
15
16
|
dir() {
|
|
16
|
-
const dir =
|
|
17
|
-
assertNoLinks(this.ctx.dataPath, dir);
|
|
17
|
+
const dir = hostDataFolder(this.ctx.dataPath, 'logs');
|
|
18
|
+
assertNoLinks(hostDataRoot(this.ctx.dataPath), dir);
|
|
18
19
|
return dir;
|
|
19
20
|
}
|
|
20
21
|
/** Log files, newest first. */
|
|
@@ -34,7 +35,7 @@ export class LogsService {
|
|
|
34
35
|
/** The newest log, or a UserError when there is none yet. */
|
|
35
36
|
newest() {
|
|
36
37
|
return (this.files()[0]?.path ??
|
|
37
|
-
fail('No sandbox logs yet in ' +
|
|
38
|
+
fail('No sandbox logs yet in ' + hostDataFolder(this.ctx.dataPath, 'logs') + '.', 'Logs appear after the first start (sandbox claude).'));
|
|
38
39
|
}
|
|
39
40
|
/**
|
|
40
41
|
* What was written to `file` since offset `from` (0 = the end of the log), as text safe for a terminal, and where
|