Commit Graph
184 Commits
Author SHA1 Message Date
saphidandClaude Opus 5.5 094c12c6d8 Keep media playing through headset standby
Real-Frame testing (2026-09-29) found an unworn headset enters standby
within seconds; SetOverlayRaw then returns RequestFailed (23) and the
movie died. The player now drops frames during standby, keeps audio
and pacing, re-sends stills and the theatre surround after waking, and
only errors after five minutes without an accepted frame.

A Stop arriving while the player is already shutting down is ignored,
so a finished video stays 'ended' instead of 'error: Stopped'. The
status now reports the layout's real source (filename/metadata).

Docs record the end-to-end device matrix (API, web UI, CLI).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-29 11:54:05 +10:00
Alex SouthwellandClaude Opus 5.5 e702adbd77 Live view: a Desktop view that stays still, and Control to tap on the Frame (#46)
* Live view: a Desktop view that stays still, and Control to tap on the Frame

The live view gets a second source and a way to use the Frame from it:

- Desktop: the app panel in use in the headset, streamed from its own window
  (x11grab of gamescope's redirected window), so it doesn't move as the
  wearer looks around. A picker shows any other panel, view only.
- Control: on the Desktop view a tap or click lands exactly where you put it;
  drag is a mouse drag, press and hold right-clicks, two fingers scroll, and
  on a computer the mouse, wheel and keyboard work directly. On the headset
  view the view is a trackpad. A text field and key row type from a phone.

Input goes through gamescope's own EIS socket (the way Steam feeds Remote
Play input) with the libei already on the image: ui/frame_touch.py, over
the same long-lived ssh machinery as the keyboard agent, nothing to
install. It reaches the panel that has focus on either X display, which
the KDE Connect route can't. Verified on the Frame and from the iPhone app
in the Simulator.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* Control: fixes from review

- Keys held on the Frame are released with buttons when Control stops or
  the view loses focus; keys for the Frame no longer trigger Frame Control's
  own shortcuts.
- Taps only act when the picture on screen is the panel in use; positions,
  presses, keys, text and scrolls name their panel (display and window: ids
  repeat across :0 and :1, told apart by pid), and the Frame drops them if
  focus has moved on. Releases always go.
- While connecting, a tap keeps its position; on an error only releases wait
  and retries back off; trimming a long queue never drops a release.
- Lifting one of two scrolling fingers ends the scroll; a cancelled touch
  isn't a tap; clicks and holds on the bars around the picture do nothing.
- A capture loop from before a Live restart can't stop the new video.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* Control: close the targeting gaps from the second review

- The focused panel's display comes from GAMESCOPE_FOCUS_DISPLAY (gamescope
  packs ":1" into the first value), so a window id repeated across :0 and :1
  can't be mistaken; the pid is only the fallback.
- Presses, keys, text and scrolls read focus afresh on the Frame; only moves
  use a reading up to a second old.
- A gesture remembers the panel it started on and does nothing more if that
  stops being the one in use; a press with no panel to aim at isn't sent.
- Opening a screenshot clears the panel Control would act on; switching to
  another app releases held keys and buttons.
- Trimming keeps a click with its position; the error backoff holds for new
  input too.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* Control: fixes from the SWE-2 Max review

- The Frame side tracks keys as well as buttons and lets go of both when the
  session ends.
- A stale tap tells the page, which re-reads the panels at once.
- A paused input device waits instead of ending the session; only a
  disconnect does. An OS error on one event skips it.
- Presses check focus with two property reads and do the full lookup only
  when it changed.
- Writes to an agent's stdin are serialized, so two devices sending at once
  can't tear a line (the keyboard agent too).
- Connecting gives up with a message after 15 s instead of hanging on
  "Connecting…"; text goes in 100-character pieces so releases don't wait
  behind a long paste; a cancelled mouse gesture releases what's held.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* Control: stale clears, pauses reconverge, pastes split per request

- The Frame says it has caught up as soon as an aimed event lands after a
  stale one, so the page stops re-reading the panels.
- After a device pause it lets go of everything it holds (releases that
  arrived while paused were dropped), and waits for the device once per
  batch, not once per event.
- The quick focus check no longer freshens the panel geometry's age.
- Each request carries at most about 100 characters of text.
- Turning Control off while it connects doesn't report an error.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* frame_touch: build the socket path on the Frame, so Windows can import it for tests

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* frame_touch: any event that goes through clears the stale flag

A trackpad move names no panel, so waiting for an aimed event could leave
the page re-reading panels for the rest of the session; a release still
aimed at the old panel doesn't count.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-29 11:13:21 +10:00
Alex Southwell ef56025ad1 Merge pull request #19 from saphid/frame-input
Keyboard and trackpad for the Frame, through its own KDE Connect
2026-09-29 10:33:35 +10:00
Alex Southwell 697452e5a9 Merge pull request #42 from saphid/theatre-media
Add owned Frame-side theatre and stereo media previews
2026-09-29 10:27:40 +10:00
saphidandClaude Opus 5.5 4bb7a1ee86 Merge main into frame-input: keyboard and trackpad alongside analytics, the Mac view and MCP
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-29 10:25:26 +10:00
saphid ae7f733b90 Merge remote-tracking branch 'origin/main' into theatre-media
# Conflicts:
#	ui/server.py
2026-09-29 10:21:27 +10:00
saphidandClaude Opus 5.5 b00db2484d Keep the backslash upload-name test POSIX-only
Windows treats the backslash as a separator, so that name can't occur there.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-29 10:15:37 +10:00
Alex Southwell 363497fdd5 Merge pull request #20 from saphid/vr-apks
Run Quest and other VR APKs on the Frame: VR detection, launcher fix, OpenXR 1.1 compatibility layer
2026-09-29 10:13:11 +10:00
Alex Southwell ff52f50c0c Merge pull request #22 from saphid/mac-in-headset
Mac in the headset: Mac windows as panels, measured and adapting to the network
2026-09-29 10:12:46 +10:00
saphid b0d6039eec Merge remote-tracking branch 'origin/main' into theatre-media
# Conflicts:
#	docs/testing.md
#	ui/server.py
2026-09-29 10:08:45 +10:00
saphidandClaude Opus 5.5 48158d1fe9 Merge main into mac-in-headset (README index)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-29 10:05:27 +10:00
saphidandClaude Opus 5.5 86b8ab1d82 Assert the start-failure test reaches systemd-run
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-29 10:01:17 +10:00
saphidandClaude Opus 5.5 e288946b81 Merge main into vr-apks: VR installs report through install_hooks like every other install
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-29 09:58:55 +10:00
Alex Southwell 66b6d46e0e Merge pull request #37 from saphid/flat2vr-mods
docs: record VR mod feasibility and own-manager requirements
2026-09-29 09:57:59 +10:00
saphidandClaude Opus 5.5 d970107716 Merge main into mac-in-headset: the Mac view alongside analytics and Report a problem
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-29 09:57:35 +10:00
Alex Southwell 6fbc450eea Merge pull request #17 from saphid/analytics-and-updates
Analytics, self-update and Report a problem
2026-09-29 09:55:12 +10:00
saphidandClaude Opus 5.5 f7573e3565 Merge main into mac-in-headset (MCP agent routes alongside the Mac view); skip the bash syntax test on Windows
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-29 09:41:24 +10:00
Alex Southwell 4f6d40625a Merge pull request #36 from saphid/linux-vr-streaming
docs: Linux VR feasibility and first-party streaming options
2026-09-29 09:39:01 +10:00
saphid c6ed6c9ea1 Merge remote-tracking branch 'origin/main' into analytics-and-updates
# Conflicts:
#	docs/frame-control.md
#	ui/server.py
2026-09-29 09:38:44 +10:00
saphidandClaude Opus 5.5 020e3386e1 Make media stop race-free and cover start failures
Stop always calls systemctl and treats exit 5 (unit already collected)
as done, so there is no is-active/stop race. Cleanup never masks the
copy error, the play ssh timeout covers the remote worst case, and
tests cover stop exit codes and systemd-run stderr reporting.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-29 09:30:03 +10:00
Alex Southwell 6d03317970 Merge pull request #15 from saphid/docs-announcements
Docs: house style for announcing features and fixes
2026-09-29 09:26:22 +10:00
saphidandClaude Opus 5.5 f81f70ed5d Fix media stop, upload cleanup and review findings
- Stop is a no-op when the collected player unit is already gone
  (raw systemctl stop exits 5 on the Frame; verified 2026-09-29).
- Surface systemd-run stderr when the player can't start.
- Keep the copy error if the cleanup ssh also fails; reject upload
  names that the play path can never accept.
- Allow 60 s for play (ffprobe 30 s + systemd-run 15 s remote).
- Docs: four-hour cap is unconditional; no delete action yet; fix a
  garbled timing sentence.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-29 09:22:22 +10:00
Alex Southwell 976008065f Merge pull request #16 from saphid/keep-awake
Keep the Frame awake during agent work
2026-09-29 09:16:03 +10:00
Alex Southwell 8b5ada1272 Merge pull request #35 from saphid/frame-mcp
Add Frame Control MCP tools and an opt-in assistant panel
2026-09-29 09:04:49 +10:00
saphidandClaude Opus 5.5 48a9914124 Skip reverse-DNS lookup when binding the loopback server
HTTPServer.server_bind calls socket.getfqdn, which stalled past the MCP
backend's 10-second startup window on GitHub's macOS runners.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-29 08:54:17 +10:00
saphid 002c859572 Set up self-contained MCP startup and inspect Frame computer-use capabilities 2026-09-29 08:18:47 +10:00
saphid 4d4e45f622 Pin fake Frame data directory modes 2026-09-28 22:46:00 +10:00
saphid 6ecd0cea39 Match fake Frame user data ownership to the headset 2026-09-28 22:44:14 +10:00
saphid c335cd5130 Fix media test portability and e2e discovery 2026-09-28 22:37:28 +10:00
saphid 0d448ab510 Add owned OpenVR media playback and stereo previews 2026-09-28 22:33:50 +10:00
saphid b5cf8253e6 Bind approval UI to current request and verify panel cleanup 2026-09-28 22:29:18 +10:00
saphid beccfec307 docs: record Frame mod feasibility and manager requirements 2026-09-28 22:25:05 +10:00
saphid a6137351d9 docs: record Linux VR client blockers and streaming options 2026-09-28 22:23:19 +10:00
saphid 6a8e3fadbf Open assistant on Frame and document verified agent workflows 2026-09-28 22:21:22 +10:00
saphid 643cb65c79 Add key-free MCP tools, human approvals and opt-in assistant 2026-09-28 22:21:22 +10:00
saphidandClaude Opus 5.5 1b90c64b73 Docs: benchmark with the headset worn (Wi-Fi much rougher; controller bounded latency)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-28 22:02:05 +10:00
saphidandClaude Opus 5.5 41f08ac9a2 Bundled KDE Connect: one safety net for every launch failure
Any unexpected error while launching clears the launch and reports it, so
the pad can always be started again; the temporary stderr file is made
inside the handled path and a failure reading it is tolerated.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-28 22:01:09 +10:00
saphidandClaude Opus 5.5 98a5ec45bb Bundled KDE Connect: tidying up can't leave the pad stuck starting
discard() swallows OSError as well as Failure, so a launch that fails and
can't remove its copy still reports the error and can be started again.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-28 21:56:00 +10:00
saphidandClaude Opus 5.5 e4421d966a Bundled KDE Connect: the server owns a copy until its agent speaks
The agent holds its copy from its first status line on and tidies it up
however it ends. Before that (a launch error, or stopped before the agent
ran) the server removes the copy itself. discard() only ever removes
incoming copies, never the iPhone bundle's own. The retry race test waits
for both contenders' decisions instead of sleeping.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-28 21:51:02 +10:00
saphidandClaude Opus 5.5 39afb23d97 Docs: Steam's StartDesktopStream pairs the Frame with the Mac (verified); stream test next
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-28 21:45:52 +10:00
saphidandClaude Opus 5.5 efffd72c52 Bundled KDE Connect: no copy left behind by a stop or a local read error
- A start turned off while copying removes the copy instead of starting an
  agent that would be killed before it could tidy up.
- A local read error while copying removes the partial copy too.
- The retry race test holds the new start until the retry has decided, so
  it fails every time without the fix (checked 3/3), not by luck.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-28 21:44:02 +10:00
saphidandClaude Opus 5.5 bda9d77d2d Mac in the headset: USB route keeps a configured host-key alias and falls back to the network
Review round 12: a failed USB-C tunnel now retries the normal path; an
existing HostKeyAlias wins; --host with --usb is rejected; the Steam
desktop-streaming claim is now 'untested' (Valve documents the desktop
showing when a game loses focus); the Show/cleanup overlap test blocks
for real (it fails without the lock). Verified live: with the cable out,
the route is the normal path.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-28 21:39:40 +10:00
saphidandClaude Opus 5.5 d5e8193ce5 Bundled KDE Connect: tidy the copied packages however a start ends
- Each start keeps its copy (holding a lock on it) until it ends, however
  it ends, then removes it; a restart can still unpack it.
- The server removes a partial copy when copying fails.
- Other copies are removed only when unlocked and over an hour old.
- Tests: a start racing the need-packages retry (one agent, not two), a
  restart that must unpack its copy, a held copy surviving the sweep.
  Both regression tests fail without their fix.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-28 21:36:22 +10:00
saphidandClaude Opus 5.5 4fae62ba14 Mac in the headset: use the Frame's USB-C network when plugged in; Steam streaming findings
- Plugged into the Mac, the Frame is a USB network device ("Steam Frame",
  usb0 at ~0.9 ms). The tunnel uses it when the Frame's usb0 answers,
  with the usual host key; otherwise the normal path. Interleaved runs:
  content p50 7 vs 10 ms, click to drawn 17 vs 27 ms, scroll p95 23 vs
  31-37 ms. FRAME_MACVIEW_USB=0 turns it off; the card says "over USB-C".
- Bench: --usb, and the route is recorded per run.
- Docs: Steam's own streaming (no SteamVR host on macOS; Remote Play pairs
  but streams games, not windows; test blocked); the Frame's USB network;
  the 2026-09-28 health-check boot-loop recurrence.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-28 21:33:31 +10:00
saphidandClaude Opus 5.5 6765fbcb20 Bundled KDE Connect: close the races the second review found
- The need-packages retry only runs if no start() has taken over, so two
  agents can't end up running for one session.
- Each copy goes to its own incoming folder; the agent removes its own once
  connected (and any a cancelled start left over an hour ago), so a stopped
  start can't delete files another is copying or still needs.
- A missing package folder means need-packages, not an error.
- Tests keep fake agents running, so they check ready and which agent owns
  the session, plus a bounded retry and the tidy rule.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-28 21:28:10 +10:00
saphidandClaude Opus 5.5 75b2478a55 Bundled KDE Connect: fixes from review
- iPhone build fails if the bundle can't be made, instead of shipping a
  stale archive with an empty version.
- A different build that another device is using right now is left running
  and replaced once nobody is, rather than stopped under them.
- If what's installed changed after the server looked, the agent asks for
  the packages (need-packages) and the server copies them and starts again.
- The installed-build check sends bytes, so Windows' CRLF can't break it.
- Starting again while a stopped start is still copying launches anew;
  concurrent copies use their own temporary names.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-28 21:18:56 +10:00
saphidandClaude Opus 5.5 1d05f57fbf Mac in the headset: a Show waits for a viewer cleanup already in progress
Review round 11: the cleanup's check and pkill now hold a lock that Show
takes to count itself in, so a new viewer can't start between them.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-28 21:14:27 +10:00
saphidandClaude Opus 5.5 484a50a189 Mac in the headset: no viewer cleanup while a Show is launching; relay pump always ends
Review round 10: a Show replacing its own stream could have its new viewer
ended by the cleanup; a viewer reset left the delayed relay pending.
Verified: the relay delivers what's queued, then closes the agent side.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-28 21:11:26 +10:00
saphidandClaude Opus 5.5 7f769ca2f0 Mac in the headset: end the Frame's viewer browser after Stop; relay fixes
- Chromium on the Frame outlived its last viewer window (verified: 11
  processes left after a run). Once nothing is shown, Stop ends it, unless
  Show was pressed again meanwhile; its profile is Frame Control's own.
- Relay --delay: if the agent side fails, close the viewer side too
  (review round 9).
- Docs: the final scroll run captured 57 fps; don't blame ScreenCaptureKit.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-28 21:07:59 +10:00
saphidandClaude Opus 5.5 5bf1268c82 Ship KDE Connect inside Frame Control instead of downloading it on the Frame
The keyboard and trackpad no longer fetch KDE Connect from Valve's package
repository on the Frame. The desktop apps and the iPhone app's Frame bundle
carry Valve's arm64 build of kdeconnect 24.02.2-1 and the five libraries it
links (kcontacts, kpeople, modemmanager-qt, pulseaudio-qt, libfakekey),
pinned by SHA-256 in frame/kdeconnect/packages.json and downloaded at build
time from the kdeconnect-frame-24.02.2-1 release, which also holds Valve's
complete source package for each.

On first use the computer copies them over its SSH connection (the iPhone
bundle already has them on the Frame); the agent checks each SHA-256,
unpacks them and stamps which build it is, so later starts copy nothing.
No internet on the Frame, 3.6 MB instead of 8 MB, 18 MB unpacked instead of
82 MB (ModemManager and friends were packaging-only dependencies).

GPL/LGPL compliance: frame/kdeconnect/NOTICE.md names each exact version,
licence and source; per-project licence texts in frame/kdeconnect/LICENSES;
THIRD_PARTY_NOTICES.md; an About and licences dialog in the app.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-28 21:07:20 +10:00