- frame_apk: android: attributes win over same-named attributes in
other namespaces; string attributes that keep only a typed value (no
raw string) still resolve; a failed icon read leaves the icon out
instead of failing the install.
- The clipboard IPC origin check can't throw on odd frame URLs.
- fetch-deps.js: 60 s download timeout, at most 5 redirects, a SystemRoot
fallback for tar.exe, and prunes pydoc_data, venv and the static
libpython.
- Docs keep the clipboard-tool note for running the UI in a browser.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The bundled Python only trusts roots already in the Windows certificate
store, which Windows fills lazily, so on a new install Steam store
search, F-Droid downloads and the compat DB failed with
CERTIFICATE_VERIFY_FAILED. fetch-deps.js now also bundles curl's pinned
copy of Mozilla's CA list, and the server adds it to the default HTTPS
context on top of the system certificates (before any urlopen, since
urllib keeps the context it first builds).
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
chromium-xr.sh steam adds a non-Steam shortcut through Steam's DevTools
port. Chrome's flags move into frame/chromium-xr/launch.sh, which both the
shortcut and launch run.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- app/build/fetch-deps.js downloads a standalone Python 3.12
(python-build-standalone) for every build and adb from Google's
platform-tools, pinned by SHA-256, and prunes what the server never
uses. It replaces the Windows-only embeddable Python.
- The app runs the bundled Python with -I -u -B -X utf8, so a PYTHONHOME
or PYTHONPATH meant for another Python can't break it and nothing is
written inside the signed macOS bundle.
- An adb you already have still goes first, so two adb versions don't
keep restarting each other's server. arm64 Linux has no official
platform-tools and keeps using the system adb.
- ui/frame_apk.py reads APK badging (package, label, version, min SDK,
ABIs, icon) from the binary manifest and resources.arsc, replacing
aapt2. It matches aapt2 on nine F-Droid APKs and finds launcher icons
the old path missed with adaptive icons.
- The app reads the computer's clipboard through Electron, so Linux no
longer needs wl-clipboard or xclip.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
From the SWE-2 Max review of the Chromium XR results: note that the
unauthenticated DevTools port is tailnet-reachable with userspace
Tailscale, say the SO_PEERCRED patch is inert while launch disables
seccomp, link panel-on-frame.sh to the script, and describe the disk
guard accurately.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- Child processes never inherit the server's stdin. Under the app it's the pipe
held open for --exit-on-eof, and Windows' ssh.exe waited on it forever, so
captures, the screenshot list and Android apps timed out.
- frame_connect's key check accepts a first-seen host key (as the copy step
does), so an already-authorized key doesn't trigger a password prompt.
Verified on Windows 11, Ubuntu and macOS against a Steam Frame: status,
headset and desktop captures, live video, library, Android apps, screenshots
and upload.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- lxterminal and tilix take the command as one string after -e.
- Refuse quotes and % in Windows terminal commands instead of a bogus escape.
- frame_connect validates FRAME_ALIAS and FRAME_USER before writing ~/.ssh/config.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- Run the server with -X utf8: the bundled Windows Python ignores PYTHON* variables.
- Quote every argument in Windows terminal commands, so cmd metacharacters are literal.
- frame_connect: accept HOST:PORT, validate input, retry the config swap while
Windows' ssh.exe holds ~/.ssh/config locked, and don't apply 0o700 on Windows.
- Never use rsync on Windows; unbounded stream queue; validate FRAME_ALIAS;
more Linux terminals; bundle the window icon; docs and wording fixes.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- Without the maintainer's key, Android compatibility reports stay on the
Mac and the UI says so; the shared database is never contacted.
- Remove personal infrastructure details from scripts and docs: the Drive
folder and gog wrapper now come from the environment, and the Chromium
build host is required instead of defaulted.
- Add an MIT license, tester instructions in the README, and bump to 0.2.0.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Live in the headset view now streams video instead of polling stereo
screenshots (~2 fps). SteamVR's steamvr-v4l2cam.service mirrors the headset
view into /dev/video99; ffmpeg on the Frame encodes it with x264 (720p30 by
default, AUD + repeated SPS/PPS), /api/stream relays the raw H.264 over SSH,
and the page splits it on access unit delimiters and decodes it with
WebCodecs into the existing viewer. Capture still takes a stereo still; the
desktop panel keeps capture polling, and the page falls back to it if the
video can't start.
The remote ffmpeg runs under a shell that kills it when the SSH channel
closes, stderr goes to a temp file, and a 10 s stall ends the stream. One
stream at a time; a new one supersedes the last.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Flathub Chromium can't enter immersive WebXR on Linux because upstream
only wires the OpenXR device on Windows. Document why, and add scripts to
cross-compile arm64 Chromium with the unmerged Linux OpenXR CLs and to
install, launch and check it on the Frame.
The first build is still running; immersive-vr support is unverified.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- Screenshots: list the Frame's Steam screenshots, open them in the
viewer, and save new ones to ~/Pictures/SteamFrame. Ids are validated
before any shell, and copies land atomically.
- Tailscale: scripts/tailscale-on-frame.sh installs a userspace tailscaled
as a lingering systemd --user service with no sudo, SHA-256 checked, safe
to re-run, with --uninstall. docs/tailscale.md covers setup and warns that
in userspace mode every Frame port, including loopback-only DevTools and
ADB, is reachable from the tailnet.
- push-vr-video.sh: filenames starting with "-" are safe, symlinks are
followed, and a real Videos\VR directory triggers a warning.
- Tests cover the screenshot routes (19 total).
Docs keep placeholder addresses for the headset and tailnet.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- app: startup shell, python and ssh probes run asynchronously so a slow
shell profile can't freeze the window; PATH comes from the user's real
login shell and a failed lookup isn't cached; a server that never
answers is killed; the setup offer runs once per launch, only after the
UI loads, and decides from HostName alone; connect.sh is started through
`env ... zsh` so it works whatever the login shell is.
- server: volume validates the level before muting or changing anything.
- Steam: null-safe install-manager fields, http.client errors caught in
store ratings, price fallback when a sale has no final price.
- tests: server output kept for diagnosis, any startup error retried, and
captures asserted non-cacheable.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Package the Frame Control web UI as an installable Electron Mac app and
bring in the tooling built alongside it.
- app/: Electron wrapper that starts ui/server.py on a free loopback port,
hardened window (sandbox, no navigation, runAsNode fuse off), login-shell
PATH so Homebrew tools work from Finder, first-run offer to run
connect.sh, ad-hoc signed DMG/zip via electron-builder.
- ui/: headset view (OpenVR screenshots), device status, library, Steam
"Get games" (owned games, install, store search), Android apps as
persistent Lepton instances with a rated F-Droid catalogue and a private
compatibility database, Android display controls over ADB, file and
clipboard transfer, Flatpaks, remote and power actions.
- apk-catalog/, compat-db/, frame/: catalogue build pipeline, Lakebed
capsule for compatibility reports, Frame-side launchers.
- tests/ and CI: server guard and validation tests plus Steam helper tests,
run on Python 3.9 with script and app syntax checks.
- Docs: README leads with the Mac app; new Android, panels, Steam games and
field-notes docs; security notes on LAN-exposed ADB ports.
Screenshot values for the headset's IP and Wi-Fi name are placeholders.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Borrows the nested Plasma session's display and D-Bus variables from
plasmashell and starts the app detached. Tested on the Frame: error paths,
argument quoting, ~ expansion, and `mac-screen` opening a VNC connection.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The headset desktop is nested Plasma in gamescope with no wl-copy/xclip,
so paste-to-frame.sh now calls Klipper over plasmashell's D-Bus bus.
connect.sh, push.sh, paste-to-frame.sh and install-apps.sh were exercised
on SteamOS 0.3.0 (build 20260922); docs record what was confirmed.
Cross-provider review skipped at Alex's request (Astra quota exhausted).
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
README with the minimum-typing checklist (Developer Mode toggle + Set User
Password; the rest runs from the Mac), docs for SSH, streaming, file
transfer, and open questions with sourced confidence levels, plus Mac-side
zsh helpers and a fallback headset bootstrap.
Scripts are UNTESTED against hardware: checked with zsh -n / bash -n /
shellcheck only. Two SWE-2 Max read-only review passes (devin -p --model
swe-2-max); verified findings fixed.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>