Commit Graph
58 Commits
Author SHA1 Message Date
spoopyghosty0 455bc987b2 Docs: the Room tab (experimental) in the README features, INSTALL.md and the site's app tour; showcase shots room + room-editing from a made-up bedroom (bed under a wall TV, desk with two monitors under a window, closet, door, lamp, plant; noisy scan mesh, clean-up report and labels to match); steps open_room / room_editing 2026-10-19 00:23:57 -04:00
spoopyghosty0 91f73fbd03 ui_smoke: Room tab editing steps (clean-up, more settings, box selected, doors, a suggestion taken, applying, applied); the pretend Frame cleans up and saves rooms; docs 2026-10-19 00:23:56 -04:00
spoopyghosty0 feda5f4a03 Docs: the Room tab (INSTALL.md, CLAUDE.md UI notes) 2026-10-19 00:23:20 -04:00
spoopyghosty0 49de808650 Document Quest controller modes and integration checks 2026-10-17 21:36:35 -04:00
spoopyghosty0 39fefd225f Steam library scheduling: now / later / off (#305)
Installing on the Frame restarted Steam to add the shortcuts, which also closed FramePort running there.
Settings -> Installing gets a Steam library mode: now (as before; restarts also wait while FramePort runs on
the Frame), later (no restart: Steam's next start re-applies and verifies the shortcuts through bounded
steam.service hooks) or off (no shortcuts; Play starts the game from FramePort). Restart Steam now bypasses
the holds and asks before ending a running game. Agent v99.

Based on the feature branch's two commits (a311498, cf05ce2), merged onto main.
2026-10-17 16:23:26 -04:00
spoopyghosty0 d0dbbe32e5 Save backups for Quest games (discussion #352)
Agent v94: _backup_saves / _restore_saves stream a tar.gz of a game's internal
and external Android storage over the SSH exec channel (caches, IL2CPP and
shader caches, FrameBridge files, videos/OBBs and files over 64 MiB left out;
manifest with sha256 last). File work runs in podman unshare, holds the
launch lock and is refused while the game runs. Restore treats the archive as
untrusted (confined paths, no links/devices, size limits, hashes checked,
staged first), keeps the replaced saves as saves-before-restore.tar.gz (undo)
and puts them back if swapping fails.

PC: install/saves.py (save-backups/<pkg>/, keep 10 by default), game menu
section Saves (back up, restore..., open backups folder), Frame page
"Back up all saves", back up before deleting saves on uninstall, Settings ->
Data keep count, CLI frameport saves backup|list|restore|undo.
2026-10-16 11:47:07 -04:00
spoopyghosty0 6101314ce1 Library folders list + scans relink moved games (discussion #351)
Settings -> Library folders lists the folders Rescan scans (scan.roots: status,
games from each, remove, Add folder...), CLI frameport folders / rescan.
A scan that finds a library game elsewhere whose own files are gone and that
is the same build points the entry at the new place (title, tags, art, user
recipe, builds and installs stay); another version is taken only by Scan a
folder... (as Update with a newer APK/version), Rescan reports it; a second
copy leaves the existing one. A full scan no longer overwrites a user recipe.
2026-10-16 10:37:11 -04:00
spoopyghosty0 39e1762e53 Game menu: Update with a newer version… for Linux apps and PC VR games (#161)
Follow-up to "Update with a newer APK…": Linux apps take their new AppImage/archive or folder (a file or a folder
picker, like the app was added), PC VR games their new game folder. pipeline.replace_linux_app / replace_rift_game
re-run the add path (add_linux_app(replace=) / add_rift_game(replace=)): the entry keeps its package (so the Steam
shortcut), name, artwork, tags, switches and the user's recipe; a folder keeps the program chosen before if it's still
there, else FramePort picks again (and asks, for ambiguous PC VR games). A name that looks like another app's is
allowed with a heads-up.

The entry gets a new source_id, recorded in the deployment's recipe at install (no agent change):
components.source_replaced shows the Frame copy (and a PC install, pc_outdated) as outdated until then. Such an
install also re-sends same-size files changed after the last install (installer.changed_since), since uploads
otherwise skip files the Frame has with the same size. The old PC VR folder is left out of later scans
(replaced_dirs). CLI: frameport new-version <game> <path> (APKs too). Docs: INSTALL.md.
2026-10-15 20:10:50 -04:00
spoopyghosty0 32a2694b05 Recover windowless FramePort instances when Windows hides the lock owner 2026-10-13 20:46:47 -04:00
spoopyghosty0 423b2e1c3e Rename… for every library entry: the name is kept from then on and reaches Steam without a new shortcut (agent v77 rename)
Game menu (Library right-click, game page "Name and artwork") and CLI 'frameport rename <pkg> "<name>"|--reset'.
The title is locked (title_locked + auto_title for the reset); rescans, Rift store matches and install links only
update auto_title; a chosen name gets no Quest/Rift twin suffix. Installed copies: the Frame's deployment.json title
changes and the shortcut is rewritten with the same appid (matched by Exe), one Steam restart; PC VR installs on this
PC keep their appid too (reinstalls and library updates now record the shortcut's real appid). A Frame that isn't
connected shows "Update name on Frame" on the game page until then or the next install.
2026-10-10 21:38:56 -04:00
spoopyghosty0 c4153be8bc Docs: FramePort's overlay autostart service (agent v76), dev Frame result 2026-10-10 20:58:57 -04:00
spoopyghosty0 dccdcaab96 SteamVR overlay apps on the Frame (agent v75)
Host OpenVR overlays are composited over Lepton (Quest) games on the Frame;
Windows overlay apps register through Proton's vrclient. Detect overlay apps
(bundled .vrmanifest with is_dashboard_overlay, or OpenVR + IVROverlay +
self-registration), patch pcvr.vr_overlay and the Linux entry fields
vr_overlay/vr_overlay_autostart, agent register/unregister/launch_vr_overlay
(IVRApplications through SteamVR's libopenvr_api.so; manifest with
binary_path_linux_arm, the only key the Frame's vrserver reads). Overlay apps
skip launch tests and the Linux Steam-parent watchdog and don't count as a
running game. Probe sources in native/vroverlay_probe.
2026-10-10 20:01:07 -04:00
spoopyghosty0 da4f26197d Merge branch 'worktree-agent-ad1c44db9b43374d4' 2026-10-10 19:17:23 -04:00
spoopyghosty0 d5245aa496 Install links: FramePort's https://frameport.app/install?… page is the documented button link (pasted links parse too); README, docs, site and in-app texts no longer point to FrameDrop's buttons (its links still work). README and site: 1.0 drops the proof-of-concept line and says plainly that not every game runs 2026-10-10 19:05:22 -04:00
spoopyghosty0 deaf1f08a6 Setup line: curl -fsSL https://frameport.app/s (fail on HTTP errors, explicit https) 2026-10-10 19:00:18 -04:00
spoopyghosty0 a4f73a88b7 Merge origin/main into site
Conflicts kept main's features with the site branch's wording: the uninstall
dialog's new delete-saves option, hardware video decoding and last-session help,
new Game settings (plain labels), agent 73 (main's 72 plus the Take screenshot
command from v66). Main's new texts follow docs/STYLE.md (for example, patch/setting
instead of fix). Pages rebuilds on docs changes and daily; the CNAME file is
gone (the domain is a Pages setting).
2026-10-10 17:18:37 -04:00
spoopyghosty0 35462324bb Docs: shorter, consistent copy
README is a short overview that links to the install guide; repeated
sections are said once; Share working recipe everywhere; the setup
script names the real buttons; a shorter notice, the same as the site's.
2026-10-10 16:34:19 -04:00
spoopyghosty0 dfab8d68fd Pair Frames in Developer Mode without a click on the PC
While no Frame is connected, FramePort watches for Frames in Developer Mode (Valve's devkit mDNS, else a scan every
30 s for Valve's pairing port, one entry per Frame by host key). One that already lets FramePort in is connected; one
that doesn't is offered FramePort's key through Valve's pairing every few seconds (refused at once until "Pair new
host" is open on the Frame, then the request shows in the headset; a 45 s pause after an unanswered one). So the user
only opens Pair new host and approves in the headset.
- frame/autopair.py (no Flet, callbacks), app._start_auto_pair, setting frame.auto_pair (switch on the Steam Frame
  page, default on); never with FRAMEPORT_HOME or FRAMEPORT_NO_AUTO_PAIR (tests, screenshots).
- Checked on the dev Frame: found by the scan (this WSL PC doesn't hear its mDNS), FramePort's key recognized, no
  pairing request sent. The headset approval path needs a Frame that doesn't know FramePort yet.
2026-10-10 09:45:51 -04:00
spoopyghosty0 cdf900c6b7 Docs: the setup URL first, the other ways kept; what the Frame offers for it
INSTALL and FRAME_SETUP describe the setup line, the Allow step and the announcement; the setup command, USB cable
and Valve's pairing stay. FRAME_RUNTIME records what was checked on the dev Frame (Chromium via Steam's +, mDNS from
the Frame only on port 5353, avahi-browse not usable over SSH). README's quick start uses the line.
2026-10-10 00:23:09 -04:00
spoopyghosty0 a069c79c73 Showcase: any number of videos (docs/showcase/videos/<name>.yaml), plus an install tutorial
- record_video.py replaces record_tour.py: one storyboard per video with its output, a start state (demo or
  fresh profile, Frame connected or not, start page, live or frozen stream), setup steps before filming, filmed
  scenes and instruction cards (eyebrow, heading, numbered steps, a command, a note) for what happens outside
  FramePort. --changed-since records the videos whose storyboard (or the recorder) changed; several videos record
  in separate processes.
- videos/install.yaml: download, first start, the welcome screen's tool download, the setup command, the command
  on the Frame (card), connected, scanning a folder, installing and playing a game (81 s).
- demo_home profile "fresh": FramePort's first start (empty library, welcome screen, nothing on the Frame); its
  games wait for the pretend folder scan. Fakes for a first start: no Frame discovery on the real network, the setup
  command shows the docs' example address, a pretend tool download, steps hooks first_run and pairing_done.
- CI records changed (or named) videos; releases attach every docs/media/frameport-<name>.mp4 as
  FramePort-<name>.mp4. INSTALL.md and README link the tutorial; SHOWCASE.md documents the storyboard format.
- Cards are opened by their title in both videos (a card's middle is its Install button).
2026-10-09 10:37:22 -04:00
spoopyghosty0 4a511ca6e3 Merge origin/main into ui-refresh
Main's microSD drives (agent v63), Linux app icons (agent v64), OBB detection, re-analysis and catalog entries,
on top of the UI refresh. Our monitor modules ({"modules": [...]}) move to agent v65 (MIN_AGENT_MODULES = 65).
Main's new UI uses the refreshed components: "Move to…" is in the game page's sectioned menu (MenuState.movable),
the .obb question and the Move dialog use C.dialog, the Frame page's drive picker C.dropdown, line-style icons.
2026-10-08 17:01:24 -04:00
spoopyghosty0 ba1ed72a55 docs: Install with FramePort button (Portal glow badge: still, animated, hover SVG + 2x PNG) and INSTALL_BUTTON.md 2026-10-08 16:42:04 -04:00
spoopyghosty0 ea2cd893b4 Linux apps in Desktop Mode's menu: per-app switch on the game page, docs
The game page's "What FramePort will do" for a Linux app gets a Desktop Mode switch ("In the menu and on the
desktop", default on): kept in the library entry (desktop_entry; patches don't apply to Linux apps), passed to
finalize_linux at install and applied at once on the Frame through the agent's desktop_entry command when the app is
installed. The agent side (menu + desktop .desktop files, launcher with FRAMEPORT_DESKTOP=1, refresh for existing
installs, removal on uninstall/purge) came with agent v63. Help text desktop_entry, INSTALL/FRAME_RUNTIME/PLAYBOOK,
CLAUDE.md. Game Mode's Steam Input problem from the report is separate.

Closes #84
2026-10-07 22:46:38 -04:00
spoopyghosty0 a90a8c27dc Install to and move games to a microSD card: Frame page Storage section, game menu Move to…
The Steam Frame page lists the Frame's drives (filesystem, free space, games on each; exFAT/NTFS cards say why they
can't hold games) and sets where new games go (library setting install.drive, default internal storage). Game menu
→ "Move to…" (Frame-installed games, agent v63) picks a drive in a dialog and queues a Frame job that follows the
agent's copy with progress (cancellable until the copy starts). The game page and the Frame page's installed list
show "on SD Card" / "SD Card not inserted"; a game whose card is out counts as installed, not "Not installed".
Help texts install_drive / move_game, ui_smoke --fake-frame drives + the Move dialog, docs (FRAME_RUNTIME "Where
FramePort keeps games", INSTALL, PLAYBOOK row, CLAUDE.md).

Closes #90
2026-10-07 22:46:37 -04:00
spoopyghosty0 a4e8e20fcd Library: start typing anywhere to search
- Keys typed on the Library (no dialog open, search not focused) go into the search and focus it, cursor at the end; Backspace removes the last character; Esc in a non-empty search clears it
- Pure helpers library.typed_char / should_capture (tested); C.dialog_open reads Flet's page._dialogs (snack bars don't count)
- Search hint "Type to search games and tags"
- "Add a PC VR game folder…" is now "Add a PC game folder…" (it adds Windows games too)
- ui_smoke: library-typed step types "arc" after clicking the header
2026-10-07 22:41:34 -04:00
spoopyghosty0 fc1bee2673 Menus: grouped sections with headers, Select near the top, launch test under Troubleshoot, destructive last; compact rows
- ui/menus.py (no controls): menu_sections() builds a game's menu for the Library right-click and the game page's "…" (Header entries for Artwork/Recipe/Troubleshoot, destructive items last after a divider; the page leaves out what its hero and Where-it's-installed cards offer; Type on Frame left the game menu; "Run launch test on …"; Analyze again also on the page); process_menu() for Monitor (Copy first, End…/Force quit… with distinct icons, End game… last, disabled "Protected by SteamOS")
- C.menu_items: 32 px rows, small-caps headers (dropped when empty), ICON_S icons, disabled items without a handler; C.menu_button/C.check_item; menus get a BORDER_STRONG border + shadow (PopupMenuButton and theme popup_menu_theme for ContextMenus)
- Add games menu: new labels/icons, Rescan folders at the end (toolbar button kept); docs/help updated
- Icons whose ROUNDED variant is filled are OUTLINED again (Monitor nav, Sleep, file types, …); the consistency test checks an explicit line-style allow-list
- Library Tags chip: the tag icon no longer overlaps its label
- tests/test_menus.py; ui_smoke shoots the Add games and game page menus
2026-10-07 22:30:48 -04:00
spoopyghosty0 627c05bf98 UI text: snooze for Later, Frame picker, clear labels, tr() everywhere, one vocabulary
- updates.snooze()/hidden(): the update banner's "Not now" hides a version for 24 h (update.snoozed); "Skip this version" unchanged
- Frame page: "Switch Frame…" opens a picker of remembered Frames (+ "Find another Frame…"); separate Disconnect button
- Labels: Update Steam art on Frame, Reset to suggested recipe… (asks first; pipeline.reset_recipe without the duplicated Rift branch), Uninstall from this PC…, Change program…, Share working recipe…, Force quit/End game…, ellipsis on everything that opens a dialog/picker or asks
- One Developer Mode path (Settings → System → Enable Developer Mode / Settings → Developer → Pair new host); linux_app help points to FEX
- tr() for the remaining visible strings (install status, job stages, update dialog, settings, files); this PC, recipe, program, for example, 50%, US spelling, Steam IDs, arm64
- Long callouts (live view, Type on Frame, pairing, library empty state) shortened, details in help texts
- tests/test_ui_text.py: untranslated literals, "..."/"e.g.", vocabulary, Switch Frame not wired to disconnect; snooze expiry test
2026-10-07 21:50:21 -04:00
spoopyghosty0 375b976dcd Monitor tab: a live view of the Frame while the tab is shown (running game with fps, CPU/GPU/memory/temperature/power/battery tiles with 2-minute sparklines, details: per-core load, sensors, power split, network) and its processes (filter Game / Steam & SteamVR / All, search, sort; right-click: end, force kill, end game; critical programs ask again). frame/monitor.py = session + pure helpers, C.Sparkline/MeterBar on Flet's canvas (no charts extension), ui_smoke FakeMonitorSession + --only, docs 2026-10-07 16:55:09 -04:00
spoopyghosty0 d49b3ae884 Install links: FramePort-only manifest fields (frameport.description / frameport.icon) shown in the install question and used as the game's icon and description; readable titles for bare file links; handler scripts wait for the open window to take a link (a just-closed window's heartbeat swallowed clicks on Windows), the heartbeat is removed on close, and the Windows handler runs under conhost --headless (no console flash) 2026-10-07 16:35:21 -04:00
spoopyghosty0 ec701e6e56 Install links (FrameDrop's "Install with FrameDrop" button protocol), drop files on the Library, add a lone Windows .exe, VR / flat window choice, x86_64 Linux apps through FEX
- deeplink.py: framedrop:// and frameport:// links and the pasted https://framedropvr.com/install?manifest=|url= link; manifest framedrop.install/v1; https only (http on loopback), no credentials, no LAN addresses (also after DNS and redirects), sha256 checked, cancel/mismatch leave no .part
- urlhandler.py: per-scheme registration (Settings → Install links, links.framedrop / links.frameport, default on; another program's scheme only taken on request) through a handler script that queues the link and starts FramePort (a flet build bundle can't take a URL argument); the GUI's heartbeat + link inbox
- GUI: Add games → Install from a link… and Add a Windows program (.exe)…; confirmation before any download; files dropped on the Library (packaged app); CLI frameport open-link
- patch device.display_mode (Automatic / VR / Flat window), verified on the Frame with 4XVR
- x86_64 Linux apps run through FEX (agent v61: FEX installed unattended, STEAM_COMPAT_DATA_PATH set, RootFS from SteamOS's /usr/share/guestos/fex-mesa); verified on the Frame with an x86_64 test program; triage linux-x86-no-fex
2026-10-07 16:06:40 -04:00
spoopyghosty0 360dc105e1 Type on Frame is a sidebar tab (was a dialog): the virtual keyboard is connected while the tab is shown and removed when another tab opens or the Frame disconnects; the Frame page button and the game menu open the tab, the keyboard icon on the Frame card is gone. README screenshot redone 2026-10-07 09:24:17 -04:00
spoopyghosty0 c3a34ace99 Files, Screenshots and Library: right-click menus (Files and Screenshots; on one of several selected items they act on the whole selection) and click-and-drag multi-select in all three; selection bars moved below the lists so they don't shift items mid-drag; the Files row Download button works again (Flet never awaited it); ui_smoke --gestures drives real mouse drags and right-clicks 2026-10-05 15:43:06 -04:00
spoopyghosty0 5198f704e9 Game configs update without a release: installed apps fetch catalog/games from GitHub main every 6 h (one API call + changed files only; background, cache-only loading; Settings → Data: last check, Check now, off switch; frameport catalog-update). Configs that need a newer FramePort (unknown patch, adapter setting or field, or min_app above this version) are skipped 2026-10-05 14:31:21 -04:00
spoopyghosty0 772c26d91a Connect with a USB cable: wizard "Set up with a USB cable" (live cable detection; setup command over the cable via the Frame's fixed PC address 10.86.200.234; connects right away when already set up), discovered Frames de-duplicated by SSH host key preferring USB > Frame hotspot > network, USB check fixes. Verified on the device: NCM driver-free on Windows 11, DHCP from the Frame, Frame->PC over the cable, the real setup end to end over USB, 36.9 vs 11.3 MB/s, re-finding a lost address 2026-10-05 14:24:48 -04:00
spoopyghosty0 f2cf7db507 Dev builds on demand: CI "Run workflow" (dev ticked, optional notes for testers) publishes the rolling dev pre-release with version <next patch>.dev<run>; Settings → Updates → "Install the latest dev build…" installs it like an update (automatic checks still ignore it; the next release is offered normally) 2026-10-05 08:30:05 -04:00
spoopyghosty0 bc6f6b7fe2 GUI for native arm64 Linux apps (GitHub #31): Add games -> Add a Linux app (arm64)... / folder (background job, opens the page), Linux badge + library platform filter, game page without recipe/patches (program + Change..., AppImage, OpenXR, source; missing-libraries callout), menus without conversion/recipe actions, Frame-only installs, Steam tags "Linux app on Frame"/"Linux", no Quest/Rift twins; safe local-file deletion for lone AppImages; Linux recipes don't follow the catalog; ui_smoke --linux 2026-10-05 00:06:12 -04:00
spoopyghosty0 dbabb37343 FramePort 0.7.0 2026-10-04 17:08:34 -04:00
spoopyghosty0 a5722b50a0 Windows games without VR (Reddit request): a game folder added with 'Add one game folder…' that has no VR runtime becomes a flat Windows game: only the Proton patches, a launcher without SteamGameId (Proton sets up no VR), a non-VR Steam shortcut (OpenVR=0, tag 'Windows game on Frame'), labels 'Windows game (Proton)'; no 'Play on this PC' 2026-10-03 19:38:23 -04:00
spoopyghosty0 0141bad259 Desktop on the Steam Frame: SteamVR dashboard → Launch a program → Desktop, then System → Konsole (the Steam Deck's Power → Switch to Desktop doesn't apply) — README, INSTALL, setup wizard, CLI, bootstrap 2026-10-03 18:12:12 -04:00
spoopyghosty0 6ed95684dc FramePort 0.6.1: Linux ARM64 build (CI ubuntu-22.04-arm, PyInstaller one-folder fallback; the updater picks FramePort-linux-arm64.tar.gz on ARM); tested games list docs/GAMES.md generated from the catalog (scripts/compat_list.py) 2026-10-03 12:05:59 -04:00
spoopyghosty0 7e2502a552 FramePort 0.6.0: Type on Frame screenshot in the README; sidebar keyboard icon compact next to the Frame name; docs: the shown app window is listed as Gamescope 2026-10-03 10:44:17 -04:00
spoopyghosty0 aade29982f Docs: Typing on the Frame (INSTALL), README feature, PLAYBOOK row, FRAME_RUNTIME/CLAUDE.md text-input facts; catalog count 39 2026-10-03 10:34:58 -04:00
spoopyghosty0 6a47fad8f7 README/INSTALL: step-by-step setup command for non-technical users (Desktop mode, Konsole, typing it, what happens next); Steam Frame badge instead of the status badge 2026-10-02 23:40:14 -04:00
spoopyghosty0 0f8062f881 README: short and to the point (badges, features, quick start, links); details moved to docs/FRAME_SETUP.md (what setup changes, networks and firewalls), docs/COMPATIBILITY.md, credits table to docs/ARCHITECTURE.md, game page screenshots to docs/INSTALL.md 2026-10-02 23:14:29 -04:00
spoopyghosty0 aefb5adc07 FramePort 0.5.0
Setup without root or password: bootstrap.sh turns Developer Mode on itself (Valve's steamos-devkit-mode helper,
config.vdf set with Steam stopped) and finishes as a user unit, since Desktop Mode is a nested Plasma inside
steam.service (stopping Steam ends it; systemd-run needs the real user bus). Shorter setup command
(curl -fsS <ip>:8765/<code> | bash). Valve's devkit pairing (POST :32000/register, ssh-rsa key, Settings → Developer
→ Pair new host) as a fallback that needs no connection into the PC. Firewall handling: temporary Hyper-V rule on WSL
(one UAC prompt, removed after setup), per-OS hints when nothing reaches the setup server. Flet updates serialized
(a dialog shown during a scan redraw never closed). Setup command survives page redraws. Uninstall: removes Lepton's
overlayfs work dirs (mode 000) and stale shortcuts (agent v31). Tests no longer touch the real data folder. README:
highlights, what the setup changes on the Frame, network and firewalls.
2026-10-02 22:53:10 -04:00
spoopyghosty0 70216de397 Docs: new screenshots (library, game, patches, Game settings, Steam Frame, Files), README and INSTALL cover Game settings, queue waiting/wake lock, temporary converted copies, 2D apps, sharing configs, contributing translations 2026-10-02 18:59:09 -04:00
spoopyghosty0 d1cf305c0a CLI: errors (e.g. an unreachable Frame) are one line on stderr with exit code 1, FRAMEPORT_DEBUG=1 for the traceback; clearer no-match message 2026-10-02 14:34:19 -04:00
spoopyghosty0 2dc92a090f CLI: help for every command and option, --frame described once, frame send --dest (--to kept), diag report --message (--text kept), errors on stderr, exit codes documented; INSTALL command-line overview 2026-10-02 14:21:55 -04:00
spoopyghosty0 23a47880e0 Lines within 120 columns everywhere (CI lints without exceptions); community and licence files; docs updated
- reflowed long lines (texts unchanged; generated launcher/PowerShell/README texts byte-identical)
- CONTRIBUTING, SECURITY, CODE_OF_CONDUCT, THIRD_PARTY_NOTICES; pyproject metadata (SPDX licence, authors, urls,
  classifiers, keywords)
- maintainer-only notes moved to a git-ignored CLAUDE.local.md; CLAUDE.md facts updated
- README: what kinds of apps run and how; INSTALL: PC VR and Files wording, new labels
2026-10-02 14:18:41 -04:00
spoopyghosty0 7af21e17ce Files tab: multi-select (download/delete several) and drag-and-drop uploads (flet-dropzone, packaged app only) 2026-10-02 10:47:35 -04:00