docs: document desktop screenshot command
This commit is contained in:
parent
02bad5f369
commit
d79cba3fa5
@ -7,6 +7,7 @@
|
||||
- Added `--desktop`, `--browser`, and `crabbox vnc` for optional Linux UI/browser leases, including loopback-only VNC with per-lease passwords and headless browser support without a desktop.
|
||||
- Added static macOS/Windows VNC endpoint discovery, including SSH-tunneled loopback VNC and trusted static direct VNC on `host:5900`.
|
||||
- Added `crabbox vnc --open` to start the SSH tunnel and launch the local VNC client for managed desktop leases.
|
||||
- Added `crabbox screenshot` to save a PNG from a Linux desktop lease without opening a VNC client.
|
||||
- Added a minimal XFCE desktop profile with panel/window manager for managed VNC leases.
|
||||
- Clarified static macOS/Windows VNC as existing-host access, not Crabbox-created boxes, so `--open` no longer launches an OS credential prompt unless `--host-managed` is passed.
|
||||
|
||||
|
||||
@ -35,6 +35,7 @@ crabbox config path
|
||||
crabbox config set-broker --url <url> --token-stdin [--provider hetzner|aws]
|
||||
crabbox warmup [--provider hetzner|aws|ssh|blacksmith-testbox] [--target linux|macos|windows] [--desktop] [--browser] [--profile <name>] [--idle-timeout <duration>] [--timing-json]
|
||||
crabbox run [--id <lease-id-or-slug>] [--provider hetzner|aws|ssh|blacksmith-testbox] [--target linux|macos|windows] [--windows-mode normal|wsl2] [--desktop] [--browser] [--shell] [--checksum] [--debug] [--force-sync-large] [--timing-json] [--blacksmith-workflow <workflow>] -- <command...>
|
||||
crabbox screenshot --id <lease-id-or-slug> [--output <path>]
|
||||
crabbox sync-plan [--limit <n>]
|
||||
crabbox history [--lease <lease-id>] [--owner <email>] [--org <name>] [--limit <n>] [--json]
|
||||
crabbox logs <run-id> [--json]
|
||||
@ -81,6 +82,7 @@ crabbox warmup --profile project-check
|
||||
crabbox warmup --desktop --browser
|
||||
crabbox run --id blue-lobster -- pnpm test:changed
|
||||
crabbox vnc --id blue-lobster --open
|
||||
crabbox screenshot --id blue-lobster --output desktop.png
|
||||
crabbox run --id blue-lobster --shell 'pnpm install --frozen-lockfile && pnpm test'
|
||||
crabbox stop blue-lobster
|
||||
```
|
||||
@ -232,6 +234,7 @@ Flags:
|
||||
--debug print sync timing and itemized rsync output
|
||||
--junit <paths> comma-separated remote JUnit XML paths to attach to run history
|
||||
--open open local VNC client for `crabbox vnc`
|
||||
--output <path> local PNG path for `crabbox screenshot`
|
||||
--reclaim claim an existing lease for the current repo
|
||||
--timing-json print a final JSON timing record
|
||||
--blacksmith-org <org> Blacksmith organization
|
||||
|
||||
@ -26,6 +26,7 @@ Command docs live here, one file per top-level command. Keep `docs/cli.md` as th
|
||||
- [actions](actions.md)
|
||||
- [ssh](ssh.md)
|
||||
- [vnc](vnc.md)
|
||||
- [screenshot](screenshot.md)
|
||||
- [inspect](inspect.md)
|
||||
- [stop](stop.md)
|
||||
- [cleanup](cleanup.md)
|
||||
|
||||
40
docs/commands/screenshot.md
Normal file
40
docs/commands/screenshot.md
Normal file
@ -0,0 +1,40 @@
|
||||
# screenshot
|
||||
|
||||
`crabbox screenshot` captures a PNG from a Linux desktop lease without opening a
|
||||
VNC client.
|
||||
|
||||
```sh
|
||||
crabbox warmup --desktop
|
||||
crabbox screenshot --id blue-lobster
|
||||
crabbox screenshot --id blue-lobster --output desktop.png
|
||||
```
|
||||
|
||||
The command resolves and touches the lease like `crabbox ssh`, verifies that the
|
||||
lease has `desktop=true`, waits for the loopback desktop/VNC service, then
|
||||
streams a PNG over SSH from `DISPLAY=:99`.
|
||||
|
||||
If `--output` is omitted, Crabbox writes:
|
||||
|
||||
```text
|
||||
crabbox-<slug-or-id>-screenshot.png
|
||||
```
|
||||
|
||||
Screenshots are currently supported for Linux desktop leases. Static macOS and
|
||||
Windows targets are existing host machines, not Crabbox-created desktops, so
|
||||
`screenshot` rejects those targets instead of capturing your local or home-host
|
||||
desktop by accident.
|
||||
|
||||
Flags:
|
||||
|
||||
```text
|
||||
--id <lease-id-or-slug>
|
||||
--provider hetzner|aws|ssh
|
||||
--target linux|macos|windows
|
||||
--windows-mode normal|wsl2
|
||||
--static-host <host>
|
||||
--static-user <user>
|
||||
--static-port <port>
|
||||
--static-work-root <path>
|
||||
--output <path>
|
||||
--reclaim
|
||||
```
|
||||
@ -41,6 +41,7 @@ This page maps user-facing behavior back to implementation files. Keep docs desc
|
||||
- Worker cloud-init bootstrap: `worker/src/bootstrap.ts`
|
||||
- Desktop/browser capability flags, env injection, and VNC checks: `internal/cli/capabilities.go`, `internal/cli/run.go`
|
||||
- VNC tunnel command: `internal/cli/vnc.go`
|
||||
- Desktop screenshot command: `internal/cli/screenshot.go`
|
||||
- Interactive desktop/VNC contract: `docs/features/interactive-desktop-vnc.md`
|
||||
|
||||
Bootstrap is intentionally tiny unless optional lease capabilities are requested:
|
||||
|
||||
@ -92,6 +92,8 @@ func (a App) Run(ctx context.Context, args []string) error {
|
||||
return a.ssh(ctx, args[1:])
|
||||
case "vnc":
|
||||
return a.vnc(ctx, args[1:])
|
||||
case "screenshot":
|
||||
return a.screenshot(ctx, args[1:])
|
||||
case "inspect":
|
||||
return a.inspect(ctx, args[1:])
|
||||
case "stop", "release":
|
||||
@ -145,6 +147,7 @@ Commands:
|
||||
actions Register GitHub Actions runners or dispatch workflows
|
||||
ssh Print the SSH command for a lease
|
||||
vnc Print or open VNC connection details for a desktop lease
|
||||
screenshot Capture a PNG from a desktop lease
|
||||
inspect Print lease/provider details; add --json for scripts
|
||||
stop Release a lease or delete a direct-provider machine
|
||||
cleanup Sweep expired direct-provider machines
|
||||
@ -157,6 +160,7 @@ Common Flows:
|
||||
crabbox run --id blue-lobster --shell 'pnpm install --frozen-lockfile && pnpm test'
|
||||
crabbox ssh --id blue-lobster
|
||||
crabbox vnc --id blue-lobster --open
|
||||
crabbox screenshot --id blue-lobster --output desktop.png
|
||||
crabbox inspect --id blue-lobster --json
|
||||
crabbox history --lease cbx_abcdef123456
|
||||
crabbox logs run_123
|
||||
|
||||
@ -39,7 +39,7 @@ func TestCloudInitDesktopProfile(t *testing.T) {
|
||||
got := cloudInit(cfg, "ssh-ed25519 test")
|
||||
for _, want := range []string{
|
||||
"xvfb xfce4 xfce4-terminal x11vnc xauth dbus-x11",
|
||||
"x11-xserver-utils xterm",
|
||||
"x11-xserver-utils xterm scrot",
|
||||
"/etc/systemd/system/crabbox-xvfb.service",
|
||||
"/etc/systemd/system/crabbox-desktop.service",
|
||||
"/usr/local/bin/crabbox-desktop-session",
|
||||
|
||||
@ -84,7 +84,7 @@ func defaultScreenshotPath(leaseID, slug string) string {
|
||||
}
|
||||
|
||||
func captureDesktopScreenshot(ctx context.Context, target SSHTarget, outputPath string) error {
|
||||
if err := os.MkdirAll(filepath.Dir(absOrDot(outputPath)), 0o755); err != nil {
|
||||
if err := os.MkdirAll(filepath.Dir(outputPath), 0o755); err != nil {
|
||||
return exit(2, "create screenshot directory: %v", err)
|
||||
}
|
||||
file, err := os.Create(outputPath)
|
||||
@ -105,14 +105,6 @@ func captureDesktopScreenshot(ctx context.Context, target SSHTarget, outputPath
|
||||
return nil
|
||||
}
|
||||
|
||||
func absOrDot(path string) string {
|
||||
dir := filepath.Dir(path)
|
||||
if dir == "" {
|
||||
return "."
|
||||
}
|
||||
return dir
|
||||
}
|
||||
|
||||
func runSSHToWriter(ctx context.Context, target SSHTarget, remote string, stdout io.Writer) error {
|
||||
remote = wrapRemoteForTarget(target, remote)
|
||||
cmd := exec.CommandContext(ctx, "ssh", sshArgs(target, remote)...)
|
||||
|
||||
30
internal/cli/screenshot_test.go
Normal file
30
internal/cli/screenshot_test.go
Normal file
@ -0,0 +1,30 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestDefaultScreenshotPath(t *testing.T) {
|
||||
if got := defaultScreenshotPath("cbx_123", "Blue Lobster"); got != "crabbox-blue-lobster-screenshot.png" {
|
||||
t.Fatalf("path=%q", got)
|
||||
}
|
||||
if got := defaultScreenshotPath("cbx_123", ""); got != "crabbox-cbx-123-screenshot.png" {
|
||||
t.Fatalf("fallback path=%q", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestScreenshotRemoteCommandUsesDesktopDisplayAndPNG(t *testing.T) {
|
||||
got := screenshotRemoteCommand()
|
||||
for _, want := range []string{
|
||||
`DISPLAY="${DISPLAY:-:99}"`,
|
||||
"command -v scrot",
|
||||
"scrot -z -o",
|
||||
"cat \"$tmp\"",
|
||||
"import -window root png:-",
|
||||
} {
|
||||
if !strings.Contains(got, want) {
|
||||
t.Fatalf("screenshot command missing %q:\n%s", want, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -75,7 +75,7 @@ describe("cloud-init bootstrap", () => {
|
||||
expect(got).toContain("ExecStart=/usr/bin/startxfce4");
|
||||
expect(got).toContain("systemctl is-active --quiet crabbox-desktop.service");
|
||||
expect(got).toContain("systemctl is-active --quiet crabbox-desktop-session.service");
|
||||
expect(got).toContain("x11-xserver-utils xterm");
|
||||
expect(got).toContain("x11-xserver-utils xterm scrot");
|
||||
expect(got).toContain("xsetroot -solid '#20242b'");
|
||||
expect(got).toContain("xterm -title 'Crabbox Desktop'");
|
||||
expect(got).toContain("(umask 077 && openssl rand -base64 18 > /var/lib/crabbox/vnc.password)");
|
||||
|
||||
Loading…
Reference in New Issue
Block a user