diff --git a/AGENT_TODO.md b/AGENT_TODO.md index 3189fec..b47be23 100644 --- a/AGENT_TODO.md +++ b/AGENT_TODO.md @@ -16,6 +16,8 @@ summary (newest last). ## Done +- **2026-08-13** — `pos communication scrcpy --new-display` support: new `SCRCPY_NEW_DISPLAY` config key (`pos config scrcpy`) — `true`/`yes` → bare `--new-display` (default size/dpi), `1920x1080`, `1920x1080/420` or `/240` → `--new-display=`; inline validation in `_mirror` (err runs in the main shell, not a process-substitution subshell) rejects anything else with the accepted forms. Docs: POS_CONFIG header, POS.md command+config tables, howto/communication.md Mirror section, HOWTO.md env row, usage() example. CLI pass-through `pos communication scrcpy --new-display=1920x1080` also works verbatim. Verified: harness +8 tests (40/40 green — WxH, true, WxH/DPI, /DPI, invalid-rejected, env>config, combined order), `bash -n`, `make gen && make check` green. + - **2026-08-13** — Fix `pos communication scrcpy` mirror failure on the real box (`ERROR: Unexpected additional argument:` on every mirror, bare or with flags): `_extra_flags()` ran `printf '%s\n'` with an empty array expansion, which prints one blank line; `_mirror()`'s `while read` turned that into an empty-string arg passed to scrcpy. Fix: `_extra_flags` now returns early when `SCRCPY_EXTRA_FLAGS` is empty (and `printf '%s\n' "${extra[@]}"` when set), and `_mirror` defensively skips blank entries (`[ -n "$f" ] && cmd+=("$f")`). Rebuilt the stub-PATH suite (`/tmp/scrcpy-run-test.sh`, outside the wiped `$TEST_DIR`) — 32/32 green incl. the regression (bare mirror → zero args to scrcpy) and EXTRA_FLAGS + passthrough mixed. `bash -n`, `make gen && make check` green. - **2026-08-13** — Fix scrcpy apt install on the live box: preinstall `apt install` failed with `Unable to locate package scrcpy` (Debian/Ubuntu need contrib/universe for `scrcpy`, and the apt build is older anyway). Removed `scrcpy` from `preinstall.sh` PACKAGES (kept `adb`); `scrcpy` now installs via the existing optional app `apps/media/scrcpy.sh` (GitHub latest, bundles adb) — docs (POS.md, howto/communication.md) and the tool's deps-guard error reworded to lead with that path. Re-verified: `bash -n`, stub suite 21/21, `make gen && make check` green. diff --git a/DOC/AGENT_Context_Project.md b/DOC/AGENT_Context_Project.md index 716511a..6f4b277 100644 --- a/DOC/AGENT_Context_Project.md +++ b/DOC/AGENT_Context_Project.md @@ -582,7 +582,7 @@ Use conventional prefixes: `feat:`, `fix:`, `docs:`, `refactor:`, `chore:` | `bin/pos-ai-gemini` | 311 | Chat with Google Gemini (ask, chat, models, sessions) | | `bin/pos-communication-matrix-listener` | 568 | Matrix listener: map /command → bash, run them on room messages | | `bin/pos-communication-matrix-sender` | 224 | Send messages to a Matrix room via the client-server API (send, test, login) | -| `bin/pos-communication-scrcpy` | 240 | Mirror/control an Android device via scrcpy+adb (mirror, devices, record, tcpip, connect, push, pull, screenshot, info) | +| `bin/pos-communication-scrcpy` | 248 | Mirror/control an Android device via scrcpy+adb (mirror, devices, record, tcpip, connect, push, pull, screenshot, info) | | `bin/pos-communication-telegram-listener` | 566 | Telegram bot listener: map /command → bash, run them on chat messages | | `bin/pos-communication-telegram-sender` | 221 | Send Telegram messages/files/links/stickers via Bot API (send, test) | | `bin/pos-config` | 80 | Interactive editor for the tools' runtime config (reads # POS_CONFIG: registry) | diff --git a/DOC/HOWTO.md b/DOC/HOWTO.md index 75a928c..32e74c9 100644 --- a/DOC/HOWTO.md +++ b/DOC/HOWTO.md @@ -37,7 +37,7 @@ templates (without overwriting an existing file): |------|---------|------| | `telegram.env` | `pos communication telegram sender` / `listener`, everything that alerts | `TELEGRAM_BOT_TOKEN`, `TELEGRAM_CHAT_ID` | | `matrix.env` | `pos communication matrix sender` / `listener` | `MATRIX_HOMESERVER`, `MATRIX_ACCESS_TOKEN`, `MATRIX_USER_ID`, `MATRIX_ROOM_ID` | -| `scrcpy.env` | `pos communication scrcpy` | `SCRCPY_SERIAL`, `SCRCPY_MAX_SIZE`, `SCRCPY_MAX_FPS`, `SCRCPY_BIT_RATE`, `SCRCPY_FULLSCREEN`, `SCRCPY_RECORD_DIR`, `SCRCPY_PUSH_TARGET`, `SCRCPY_EXTRA_FLAGS` | +| `scrcpy.env` | `pos communication scrcpy` | `SCRCPY_SERIAL`, `SCRCPY_MAX_SIZE`, `SCRCPY_MAX_FPS`, `SCRCPY_BIT_RATE`, `SCRCPY_FULLSCREEN`, `SCRCPY_NEW_DISPLAY`, `SCRCPY_RECORD_DIR`, `SCRCPY_PUSH_TARGET`, `SCRCPY_EXTRA_FLAGS` | | `notify.env` | `lib/notify.sh` (all alerting) | `NOTIFY_PLATFORM` (e.g. `telegram,matrix`) | | `system.env` | `pos system health`, `pos system backup` | `BACKUP_SERVICE_ROOTS`, `HEALTH_BACKUP_MAX_AGE_DAYS` | | `compose.env` | `pos docker compose` | `TS_AUTHKEY`, `TZ`, `DNS_SERVER`, `SERVICES_BASE` | diff --git a/DOC/POS.md b/DOC/POS.md index bb9345a..c648552 100644 --- a/DOC/POS.md +++ b/DOC/POS.md @@ -328,6 +328,7 @@ The daemon long-polls `/sync` (30s timeout, per-sync `since` token, compact filt | Command | Behavior | |---------|----------| | `pos communication scrcpy` | Mirror the device: opens the scrcpy window (needs a display — over ssh use `ssh -X`). Built from `scrcpy.env` defaults plus any pass-through scrcpy flags (`pos communication scrcpy --turn-screen-off --stay-awake`) | +| `pos communication scrcpy --new-display[=…]` | Mirror to a new virtual display on the phone (no need to mirror the real screen): `--new-display` (default size/dpi), `--new-display=1920x1080`, `--new-display=1920x1080/420` or `--new-display=/240`. Also settable persistently via `SCRCPY_NEW_DISPLAY` | | `pos communication scrcpy devices` | `adb devices -l` — the source of serials for `SCRCPY_SERIAL` | | `pos communication scrcpy record [file] [--headless]` | Record a session to an mp4 — default `$SCRCPY_RECORD_DIR/_.mp4`; `--headless` adds `--no-playback` (no window — headless-server friendly) | | `pos communication scrcpy tcpip [port]` | `adb tcpip ` (default 5555) — switch the USB device to wireless adb, prints the reconnect command with the detected device IP | @@ -348,6 +349,7 @@ A device must have **USB debugging** enabled (Developer options) and the phone's | `SCRCPY_MAX_FPS` | no | — | Limit frame rate, e.g. `60` (scrcpy `--max-fps`) | | `SCRCPY_BIT_RATE` | no | — | Video bit rate, e.g. `8M` (scrcpy `--video-bit-rate`) | | `SCRCPY_FULLSCREEN` | no | `false` | `true` adds `--fullscreen` | +| `SCRCPY_NEW_DISPLAY` | no | — | New virtual display on the phone (`--new-display`): `true` (default size/dpi), `1920x1080`, `1920x1080/420` or `/240` | | `SCRCPY_RECORD_DIR` | no | `~/Videos/scrcpy` | Output dir for `record`/`screenshot` defaults | | `SCRCPY_PUSH_TARGET` | no | `/sdcard/Download` | Default `adb push` destination | | `SCRCPY_EXTRA_FLAGS` | no | — | Extra scrcpy flags appended to every mirror | diff --git a/DOC/howto/communication.md b/DOC/howto/communication.md index aeff4f6..9260423 100644 --- a/DOC/howto/communication.md +++ b/DOC/howto/communication.md @@ -256,8 +256,14 @@ install the current GitHub release (bundles `adb`) with the optional app pos communication scrcpy # USB device, config defaults pos communication scrcpy --turn-screen-off # pass any scrcpy flag through pos communication scrcpy --no-audio --always-on-top +pos communication scrcpy --new-display=1920x1080 # mirror to a NEW phone display ``` +`--new-display` mirrors a fresh virtual display instead of the phone's real +screen (nice for watching the phone screen content elsewhere): no `=…` uses the +main display's size/dpi, or force size/dpi — `1920x1080`, `1920x1080/420`, +`/240`. Set it persistently with `SCRCPY_NEW_DISPLAY` in `pos config scrcpy`. + The window needs a display — over ssh use `ssh -X` (and a phone already reachable over WiFi, see below). `scrcpy --help` lists every flag; the wrapper forwards flags verbatim. diff --git a/bin/pos-communication-scrcpy b/bin/pos-communication-scrcpy index db0a5a7..2532005 100755 --- a/bin/pos-communication-scrcpy +++ b/bin/pos-communication-scrcpy @@ -2,7 +2,7 @@ set -euo pipefail # POS: communication scrcpy — Mirror/control an Android device via scrcpy+adb (mirror, devices, record, tcpip, connect, push, pull, screenshot, info) # POS_SUBCMDS: devices record tcpip connect push pull screenshot info -# POS_CONFIG: scrcpy | scrcpy.env | SCRCPY_SERIAL=:Default adb serial (from 'pos communication scrcpy devices') | SCRCPY_MAX_SIZE=:Limit video size (e.g. 1920) | SCRCPY_MAX_FPS=:Limit frame rate (e.g. 60) | SCRCPY_BIT_RATE=:Video bit rate (e.g. 8M) | SCRCPY_FULLSCREEN=:Start fullscreen (true/false) | SCRCPY_RECORD_DIR=:Record output dir (default ~/Videos/scrcpy) | SCRCPY_PUSH_TARGET=:adb push destination (default /sdcard/Download) | SCRCPY_EXTRA_FLAGS=:Extra scrcpy flags appended to every mirror +# POS_CONFIG: scrcpy | scrcpy.env | SCRCPY_SERIAL=:Default adb serial (from 'pos communication scrcpy devices') | SCRCPY_MAX_SIZE=:Limit video size (e.g. 1920) | SCRCPY_MAX_FPS=:Limit frame rate (e.g. 60) | SCRCPY_BIT_RATE=:Video bit rate (e.g. 8M) | SCRCPY_FULLSCREEN=:Start fullscreen (true/false) | SCRCPY_NEW_DISPLAY=:New virtual display (--new-display): true, WxH, WxH/DPI or /DPI | SCRCPY_RECORD_DIR=:Record output dir (default ~/Videos/scrcpy) | SCRCPY_PUSH_TARGET=:adb push destination (default /sdcard/Download) | SCRCPY_EXTRA_FLAGS=:Extra scrcpy flags appended to every mirror source "$(dirname "$0")/../lib/common.sh" 2>/dev/null || source "$(dirname "$0")/common.sh" @@ -36,6 +36,7 @@ SCRCPY_FULLSCREEN="${SCRCPY_FULLSCREEN:-false}" SCRCPY_RECORD_DIR="${SCRCPY_RECORD_DIR:-$HOME/Videos/scrcpy}" SCRCPY_PUSH_TARGET="${SCRCPY_PUSH_TARGET:-/sdcard/Download}" SCRCPY_EXTRA_FLAGS="${SCRCPY_EXTRA_FLAGS:-}" +SCRCPY_NEW_DISPLAY="${SCRCPY_NEW_DISPLAY:-}" usage() { cat < environment > config file. Examples: pos communication scrcpy pos communication scrcpy --no-audio --always-on-top + pos communication scrcpy --new-display=1920x1080 pos communication scrcpy devices pos communication scrcpy record --headless pos communication scrcpy tcpip 5555 @@ -124,6 +126,12 @@ _mirror() { # $@ = pass-through scrcpy flags [ -n "$SCRCPY_MAX_FPS" ] && cmd+=(--max-fps "$SCRCPY_MAX_FPS") [ -n "$SCRCPY_BIT_RATE" ] && cmd+=(--video-bit-rate "$SCRCPY_BIT_RATE") [ "$SCRCPY_FULLSCREEN" = "true" ] && cmd+=(--fullscreen) + case "${SCRCPY_NEW_DISPLAY:-}" in + true|yes) cmd+=(--new-display) ;; + [0-9]*x[0-9]*|/[0-9]*) cmd+=(--new-display="$SCRCPY_NEW_DISPLAY") ;; + "") : ;; + *) err "invalid SCRCPY_NEW_DISPLAY '$SCRCPY_NEW_DISPLAY' — use true, x, x/ or / (e.g. 1920x1080, 1920x1080/420, /240)" ;; + esac while IFS= read -r f; do [ -n "$f" ] && cmd+=("$f"); done < <(_extra_flags) cmd+=("$@") exec "${cmd[@]}"