bg_activity.rs polls the engine's /api/activity every second from Rust, so a
hidden or frozen WebView no longer decides whether work is running or has
ended. A pure step() turns each snapshot into start/update/finished/stop
actions: the first poll only records seq, an engine restart resets it, a
renderer hold refreshed within 5 minutes counts as work, and nothing active for
30 s stops. Finished jobs are emitted to the page (bg-job-finished, plus a
bg-tick heartbeat while work runs) and announced through the OS when the app is
in the background, in the language the page sends.
Android: a connectedDevice foreground service (dataSync as fallback) with a
partial wake lock and a Wi-Fi lock keeps the process and its in-process engine
alive, with an ongoing progress notification and a separate result channel. The
Kotlin class, manifest entries and R8 keep rules are written by
android-postinit-patch.sh. JNI_OnLoad and the context helpers move to
android_jni.rs so both callers share them; app classes load through the
context's class loader. The mobile engine start is now once per process, as
Activity recreation can run setup again.
Desktop: notifications through the notification plugin's Rust API when the
main window is hidden, minimised or unfocused; backgroundThrottling disabled on
the window (macOS 14+).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K3cPwhp3UrzayBfyy9PDcN
Engine routes /api/ps5/pldmgr{,/launch,/delete,/autoload,/store} over Payload Manager's
own HTTP API (:8084). Storing into an existing folder is confirmed first, since Payload
Manager's import removes that folder's other files. Scene-tool pills with a web page
(Payload Manager :8084, LZ4 Compression :5920) open it.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EU1Z2mdhAxBrH1yb48pxik
The sync treats every lockfile crate without a source as ours and set
the vendored sevenz-rust2 to the app version (7.0.5, 7.0.6), the same
trap unrar fell into; cargo then wrote 0.23.0 back and CI's version
check failed. It joins unrar on the vendored list, and the desktop
lockfile is back to 0.23.0. Builds were unaffected: cargo always built
the vendored source.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ub1mez9eaVtTF8pMEFXvA9
remotePlay_slot now reads "Slot {slot}" like Profile's label, which in
those four languages is identical to English, so the coverage check
called it untranslated and failed CI. Allowlisted as the same word.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ub1mez9eaVtTF8pMEFXvA9
The audit counts a script as used when its file name appears elsewhere;
require("./post-images") left the .js off, and CI's repo-scripts job
failed with post-images.js as unreferenced.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ub1mez9eaVtTF8pMEFXvA9
Release and introduction posts send downloads to ps5upload.phantomptr.com (it
picks the right file), keep the GitHub release for full notes, and the
introduction posts say who made it. scripts/post-images.js screenshots the live
website with the client's Playwright into .release_posts/website/; each post
command copies the ones it needs into its images/ and says where to attach them.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ub1mez9eaVtTF8pMEFXvA9
scripts/promo-posts.js writes .release_posts/about/: what PS5Upload is, its
features, how to start and where to download, shaped for X (a thread that
fits 280 per post, checked), Discord and Reddit, plus app screenshots to
attach. The version and link come from VERSION; release-posts.js stays the
per-release notes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ub1mez9eaVtTF8pMEFXvA9
site/ is a static page in the app's own look (light and dark, the app's
screenshots): features, downloads for every platform with the visitor's
system first, the Docker command, news from the release notes, community
links. It reads the releases from GitHub's API live, falling back on
site/releases.json (scripts/site-releases.mjs), which the pages workflow
rewrites on every deploy: after each publish run, on release edits (promoting a
pre-release), on changes to site/, and daily.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ub1mez9eaVtTF8pMEFXvA9
make release-post now writes .release_posts/v<version>/ (git-ignored): each X post
in its own file (plain text, 280 with links as 23, link in the main post), a
Discord announcement in Discord's markdown (named links without embeds, small
print), and the Reddit title and body as separate files, plus a README saying
what goes where with each post's length. Every platform gets the issues link.
Short lines keep the first clause after a label, so X no longer reads
'Convert', 'Captures'.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ub1mez9eaVtTF8pMEFXvA9
The logo was only applied when the Android project was first created, so an
existing one kept Tauri's placeholder, and the round icon was a small tile
inside a circle. scripts/release/android-icons.py draws the set from the icon
source (adaptive logo in the safe zone over white; full-bleed white tile and
disc for older launchers), and the post-init patch copies it on every build,
local and CI.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ub1mez9eaVtTF8pMEFXvA9
Pin v0.44 (sha256 4d06eab7...). Its crt/ and prospero-nid are identical
to v0.43, so the vendored sdk-crt (+ ps5upload.patch) and the portable
prospero-nid stay as they are; the helper, installer and elfldr build to
the same code (only the build-id differs). v0.44 adds LLVM 23 to the
candidate list, so the Makefile comment and Homebrew fallbacks move too.
scripts/update-ps5-sdk.sh (make update-sdk): finds the latest release
(or --tag), checks the zip, rewrites the pin, re-vendors prospero-nid
and crt only when upstream changed them (stops if our crt patch no
longer applies), moves the "SDK vX.Y" doc mentions and installs with
install-ps5-sdk.sh, keeping the old SDK as a backup. --check only
reports. The installer names its backups after the release they hold.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ub1mez9eaVtTF8pMEFXvA9
Deletes tests/install-fallback-hw.mjs, the mobile audit probe and its allowlist,
scripts/requirements.txt, tests/lab/verify-pending.sh, bench/baselines/ and client/icons/
(nothing references them; the bundle icons live in client/src-tauri/icons). audit-scripts
lists fpkg-diff.py as a manual research tool and no longer counts a script naming itself as
a reference. SPEC.md no longer says zip/7z/RAR sources fall back to FTX2.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ub1mez9eaVtTF8pMEFXvA9
- Bug report wizard (4 steps, time range, GitHub/Discord/zip), redacted on both sides.
- Engine event journal + app journal merged into one timeline; helper stderr mirrored from each PS5.
- Results that finish after a console switch land on the console they started on.
- Faster local gate and CI (nextest, parallel lanes, sharded C interop/ASan, cache restore/save).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ub1mez9eaVtTF8pMEFXvA9
New:
- Collection: every game in your folders (local or on a NAS, scanned in
place), grouped with updates and DLC, what each PS5 has, one-click
installs, install links, organize / de-duplicate / clean up. Replaces PS
Game Library (with an importer).
- Send a game folder as one image (.ffpfsc / .ffpkg / .exfat); Convert
writes .ffpkg and .ffpfs too.
- Files: Move to... (instant or cross-drive, with a fit check) and Set
permissions (777).
- Offline PSN sign-in from Profile.
Fixed:
- Android 17: local network permission (6.x could not connect).
- FW 5.50: own build of the SDK startup code, so the helper, installer and
elfldr start.
- Web UI: Send helper (pairs it); no "ready" while unpaired.
- Screenshots decode in a child process (Linux crash loop).
- Installs no longer start queued uploads.
- Cross-drive moves check the copy before removing the original.
- Finished installs show as done after a reload; engine-unreachable
explained with Restart engine; Health starts the installer.
- Dev: make run-client renders on macOS 27.
Better: "declined" installs explain Sony's code and how far it got;
0x80B21104 explained; Connection failures readable; keep-awake for all
installs; Games cards. Translations, FAQ, README.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VM5Gzyt1uxKyJiWZAgd1w9
- Fix 0x80B2116F ("The PS5 declined the install"): Sony reads 8 bytes past
the six-pointer MetaInfo we handed sceAppInstUtilInstallByPackage; ours
held stack leftovers there, which sent full packages down the patch path.
Every Upload & install was refused and Stream installs failed 3 in 5 once
the daemon had made a few on-console attempts. Installer daemon 1.3.9.
Measured on FW 13.60 on two consoles: refused every time before, accepted
every time after (3.6 GiB base over itself, and its patch).
- Each console keeps its own tree of screens across a console switch.
- Volumes: "Kept by ps5upload" with clean-up for temp and test files.
- Every Play button closes a running game first.
- Games: resume a failed Download; try a stopped or failed Move again.
- Pairing: after Resend helper, wait for the console to accept.
- Remote Play: unlocking the PS5's own setting with np-fake-signin v1.4.
- The scroll lock takes the scroll root that is on show.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- #401: a single-file upload started again (Upload screen Start, or re-added to
the queue) ran under a new job id, so the console's kept .ava-part was not
credited and the space check asked for the whole file while the partial still
took that room. The id is now remembered per (console, source, destination)
like folders, reused on the next attempt, and forgotten on success.
- #400: the console takes one turbo temperature, not a curve. The Fan Curve
screen says so and shows the temperature the points map to (same rule and
bounds as payload/src/fan_map.c).
- #399: "The PS5 declined the install" dropped Sony's error code; it is shown.
- Version 6.2.1 and its changelog entry.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01U6otJV6kLjX99ZS9GpoCS1
* chore(deps): Bump rustls from 0.23.43 to 0.23.45 in /client/src-tauri
Bumps [rustls](https://github.com/rustls/rustls) from 0.23.43 to 0.23.45.
- [Release notes](https://github.com/rustls/rustls/releases)
- [Changelog](https://github.com/rustls/rustls/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rustls/rustls/compare/v/0.23.43...v/0.23.45)
---
updated-dependencies:
- dependency-name: rustls
dependency-version: 0.23.45
dependency-type: indirect
...
Signed-off-by: dependabot[bot] <support@github.com>
* Install: drop the staged-refusal retry guard and the stream reach pre-check
After the PS5 refused a package from its own storage (0x80b2116f), the app
would no longer run Install on that row again and blocked Retry with Stream
unless the engine had offered it. Install and Retry with Stream now always
go out.
The engine no longer probes whether the console can reach it before handing
over a stream URL. A console that never fetches still gets the firewall /
PS5UPLOAD_PKG_HOST_IP explanation from the post-failure path.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vq9BzVoith72tgD87LGG2z
* Helper: everything written on the console is 0777
Since 6.0 an upload kept the computer's file modes, so a game folder sent
from Windows landed as 0644 files. The PS5's app loader refuses game files
without world-execute, so those games would not launch until the user ran
chmod 777 by hand. The 5.x helper forced 0777 for this reason.
Uploads, on-console copies and the file manager's writes and new folders
now land as 0777. fs_chmod still sets exactly the mode it is given.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vq9BzVoith72tgD87LGG2z
* Fix launch refusals, folder permissions, abandoned upload space and overestimated free space
- A launch refused with 0x80940033 now says whether kstuff is missing; with kstuff running,
a folder game is made 0777 and launched again. Folder games get a Fix permissions button.
- The helper's own ps5upload folders are 0777, and older ones are opened up on start.
- The helper's job cleanup also deletes the half-written copy of an abandoned upload.
- An upload that runs out of room part-way teaches the engine how much of that drive the
console never allocates; later space checks and Volumes' safe figure leave it out.
- Queue rows that failed because the PS5 could not reach this computer offer the
Windows firewall fix; FAQ lists the ports and the 0x80B2116F firmwares.
- lf_slots_wedge: a bound that a healthy ASan run fits.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vq9BzVoith72tgD87LGG2z
* 6.2.0: games launch again, installs stop giving up early
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vq9BzVoith72tgD87LGG2z
* i18n: add the launch-refusal and fix-permissions strings to en, allowlist them for other locales
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vq9BzVoith72tgD87LGG2z
* ava1: a finished job counts the bytes still awaiting their Received
bytes_sent grew only on a Received the send loop read, and the loop stops at JobDone. A frame
still in flight then went uncounted although the job holds it: a list upload reported 19000 of
26000 bytes under the coverage build.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vq9BzVoith72tgD87LGG2z
* ava1: a lane stopped by its LaneDown never picks a frame afterwards
A lane task checked its stop flag only at the top of its loop. One that passed the check just
before LaneDown, and reached its pick after lane_death had swept the lane, charged a frame to
the dead lane: the frame sat in inflight with no lane to carry it, nothing queued, so the stall
rule never fired and the job waited forever (the soak test's resume hung under the coverage
build). The flag is now read again under the sched lock, which lane_death's sweeps take, so a
pick is either swept or sees the stop. The pick moves into pick_for_lane for a deterministic test.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vq9BzVoith72tgD87LGG2z
* ci(coverage): run the engine tests once for both reports, 60 min limit
scripts/coverage.mjs ran `cargo llvm-cov --lcov` and then `--html`, each a full instrumented
test run. One pass now takes ~34 min, so the second ran into the 40 min limit and the job was
cancelled (it was red on main too). The tests now run once (--no-report) and both reports come
from that run's profiles via `cargo llvm-cov report`; the limit is 60 min for headroom.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vq9BzVoith72tgD87LGG2z
---------
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
* docs: 6.0.0 changelog, README, FAQ and contributor docs
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XR8fQMhp7Rdgq2e4U9oDff
* Release prep: version 6.0.0
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XR8fQMhp7Rdgq2e4U9oDff
* fix(ci): keep the leaked test pools reachable for LSan; skip the tiny-file floor under coverage
- ava1-ctest diag/mgmt_fs: the &'static Pool each test leaks for
AvaTransport::with_pool is now held in a static list, so LeakSanitizer sees
it (and the sessions on its threads) as reachable instead of reporting
~140 KB of indirect leaks the frame-name suppression could never match.
Verified under clang ASan+LSan in Linux Docker: diag 13/13, mgmt_fs 40/40.
- download.rs tiny-file throughput floor is skipped when cargo-llvm-cov runs
(CARGO_LLVM_COV set): instrumentation slows every call several times over.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XR8fQMhp7Rdgq2e4U9oDff
* fix(test): data_rust servers use the clients' fast timing
Five folder-host tests gave the client fast timing (dead after 500 ms) but
left the server on the default (ping every 2 s). On a slow runner a half-second
gap made the client drop healthy lanes and the job stalled until the 36 s
progress limit (both CI runs on #374/#377). The ordered-download tests already
set both ends; these now do too. The app uses one timing on both ends.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XR8fQMhp7Rdgq2e4U9oDff
* fix(test): the C lane socket-buffer test accepts Linux's wmem_max cap
Same cap as the Rust lane test: Linux CI gives the send side 416 KiB, so the
1 MiB floor failed under ASan in CI. 128 KiB is still far above a default.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XR8fQMhp7Rdgq2e4U9oDff
* fix(ci): gcc unused-result in the FTP selftest, serial ctest in make test, sender state on failure
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XR8fQMhp7Rdgq2e4U9oDff
* fix(ava1): flush a partial bundle after any reader message, not only a record
The last small-file record could arrive while a large file's chunk or root
was still queued behind it: the flush saw a non-empty channel, the next
message was not a record, and the records sat unsent until the receiver
cut the job as stalled (CI-only flake; 7/36 under local parallel load, 0/48 after).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XR8fQMhp7Rdgq2e4U9oDff
* fix(validate): run the C interop tests serially in make ci too
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XR8fQMhp7Rdgq2e4U9oDff
* fix(ava1): a resumed file goes in one-group pieces so a flapping link still makes progress
With kills every 2 s, the 4 MiB tail piece was cut before it was durable on every
attempt and the upload retried the same 28 MiB mark until it timed out (1 in 3
locally, CI coverage). Resumed files now send 1 MiB pieces: 5/5 in ~6 s.
Also: make docker-engine uses the repo root as context (as CI); governor
classification asserts are skipped under the sanitizers, where the C is the bottleneck.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XR8fQMhp7Rdgq2e4U9oDff
* fix(test): single-instance gate tests hold the C-server lock; relay test cap leaves margin
Coverage runs the C tests in parallel; the two gate tests stop the one global C server.
The relay order test's 4 MiB/s cap finished in 5.9 s on CI against its >6 s precondition.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XR8fQMhp7Rdgq2e4U9oDff
* fix(test): periodic-kill bound widened under coverage; tiny-file floor relaxed on CI runners
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XR8fQMhp7Rdgq2e4U9oDff
* fix(test): lane-kill test kills until a resend; periodic-kill liveness race skipped under coverage
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XR8fQMhp7Rdgq2e4U9oDff
* fix(test): a hung relay fails its test at the bound instead of hanging the CI job
The dest-ends relay test ran the relay under spawn_blocking: on a hang the timeout
panicked but the runtime then waited forever for the blocking thread (27 min on CI).
It now runs on a plain thread. The engine test steps get a 25-minute bound.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XR8fQMhp7Rdgq2e4U9oDff
* fix(test): dest-ends relay test in its own binary on small files; relay logs its silent retries
The test hung a CI job twice inside the shared relay binary (behind the 384 MiB relays'
lock) and never reproduced locally or in Linux Docker. It now runs alone, on 4x32 MiB
(still twice the relay buffer), ~3 s. The relay's open-dropped and retry paths now say
so on stderr instead of looping silently. Governor classification asserts also skip
under coverage, where the instrumented sender is the bottleneck.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XR8fQMhp7Rdgq2e4U9oDff
* fix(test): the partly-durable relay test caps its first attempt so it can be interrupted
On a fast runner the uncapped relay finished all 160 MiB before the first durable
report was observed. The first attempt now reads A through a 32 MiB/s proxy (~5 s);
the resume runs uncapped.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XR8fQMhp7Rdgq2e4U9oDff
* feat: one-time 6.0 upgrade clean-up that keeps every setting
Host (engine, once per data dir): pre-5.x files no 5.41/6.0 code reads (api_token,
ps5upload.ini, ps5upload_profiles.ini/.json, app-config.json) move to ~/.ps5upload/legacy-5x/.
App (desktop, once): the 1.x/2.x config.json/profiles.json move to legacy-5x/; the cached
ezremote-dpi.elf nothing loads is deleted. Client: the retired upload-streams key is dropped.
Console (once per console, on its first 6.0 helper answer): the FTX2 /data/ps5upload/tx and
/spool folders are deleted; a failure retries later. The health check no longer lists those
folders (its fix would have recreated them). Nothing current is moved or reset.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XR8fQMhp7Rdgq2e4U9oDff
* fix(test): the download periodic-kill race is skipped under coverage, like its upload twin
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XR8fQMhp7Rdgq2e4U9oDff
* fix(test): the tiny-zip floor only catches a stall on CI runners
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XR8fQMhp7Rdgq2e4U9oDff
* fix(test): 'other calls still answer during launches' is a state check, not a wall-clock bound
Both mgmt_t6 tests asserted a sub-300 ms answer while a slow Sony call ran; on a loaded
runner that separates nothing. They now assert the answer arrived while the slow call
was still in flight.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XR8fQMhp7Rdgq2e4U9oDff
* fix(ci): reword the 6.0 migration comments for check-no-ftx2
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XR8fQMhp7Rdgq2e4U9oDff
---------
Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
* fix: installs the PS5 declined, Docker images that work, Payload Manager as a backup loader (5.41.0)
Installs
- A package the console serves itself (Upload & install, USB, the phone app)
is refused on FW 13.60 with 0x80B2116F (Sony's DbgGetPatchInfo/DbgCancelPatch
path, especially over an installed app). The unified install now re-serves
the console's copy from the engine (ps5:// read back through the helper) and
a refused link through the engine's link proxy. HW-verified on a 13.60 Pro:
stream, Upload & install fresh and over an installed app, USB.
- Installer 1.2.0: fixed past Last-Modified, logs to /data/ps5upload/installer.log.
- NET_REACH (frame 148/149): the console checks it can reach the engine before
a stream install and names a firewall/isolation cause in seconds.
- Staged-route refusals get their own reason and message (staged_refused).
- Folder-game register on 13.x: sceAppInstUtilAppInstallAll fallback,
/system_ex rw remount on EROFS, repeated uninstall for its two records.
- Removed the incorrect "no fake packages above FW 11.60" warnings.
Loaders
- itsPLK Payload Manager (:8084) fallback: starts the installer, recovers a
wedged elfldr (HW-verified) and puts the helper back when :9021 is dead.
Only ever uses its own ps5upload-* folders.
- Setup wizard skips payloads already running; "Send only ps5upload".
Engine / self-hosting
- Engine clients ignore proxy env vars; errors carry the real cause.
- Docker: writable /tmp and /data (also under a user: override), HEALTHCHECK
via --healthcheck, PS5UPLOAD_ALLOW_IP takes CIDR ranges, actionable 403,
bridge-network warning, engine/compose.yaml, scripts/docker-smoke.sh run in
the PR gate and before every release push.
- Desktop app with a remote engine browses the engine's disk; From this device
uploads first. Android engine listens on the LAN so the phone can stream.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test: accept Windows' timeout as the probe's underlying cause
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* style: rustfmt the probe test
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* chore(android): run-android foregrounds and reuses the emulator; faster emulator
- ensure reuses a running or still-booting emulator instead of booting a
second; run-android brings its window to the front and reopens a headless
one with a window; run-android-background leaves it headless.
- A stopped emulator is waited on until it has really exited (forced after
60s), so a restart no longer mistakes it for one that is booting.
- Windowed emulators render on the host GPU instead of software, with 4 GB
RAM and up to 6 cores.
- Android dev serves Vite on 1430/1431 (PS5UPLOAD_VITE_PORT), so it can run
alongside desktop dev on 1420.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* chore(android): software rendering by default; host GPU is opt-in
-gpu host froze the Android 16 image within minutes on an M1 Max (the
emulator warns its guest GL layer is unstable above API 35), with or
without Guest ANGLE. PS5UPLOAD_EMU_GPU=host opts back in.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* fix(docker): the web UI image bundles the FAQ and Changelog
Since the FAQ and Changelog screens bundle ../FAQ.md and ../CHANGELOG.md,
the web UI image's frontend stage failed: it built the client at /src
and .dockerignore excluded every *.md. The stage now keeps the repo
layout (/repo/client) and copies the two files in.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(scripts): the audit counts a script's node:test file as used
scripts:check runs every *.test.mjs by pattern, so the test beside
stale-client-lib.mjs is named nowhere and the strict audit called it an
orphan (repo scripts failed on all three OSes).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
kill-stale-client did `pkill -f ps5upload-engine`, which SIGTERMed
every engine on the machine — a standalone one on another port died 70
minutes into a package build. It now stops only an engine listening on
19113 (an engine whose app is gone exits by itself). The decision is a
small pure module with node:test cases, which scripts:check now runs.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
release-posts.js
- Reads whole changelog groups (bold heading + wrapped bullets), not just
the first line of each bullet.
- X: link counted as 23 chars, replies packed to fit 280, markdown stripped.
- Discord: full bullets when they fit 2000 chars, short ones otherwise;
Reddit: real markdown sections instead of a code block.
- Says "pre-release" when GitHub does (gh), --prerelease/--stable to
override; --only and --out to pick a platform and write files.
- make release-post calls it directly; the .sh wrapper is gone.
Removed (outdated)
- ps5-install-trace.py, ps5-install-watch.py, fpkg-mount-test.py: drove
/api/pkg/install/start and the dpi-* routes, which no longer exist.
- gather-fakelibs.py: superseded by the app's Backport scan.
- pull_ps5_debug.py: pulled a debug dir the helper no longer writes to.
hw-test-loop.sh ran cargo from the repo root (no workspace there); it now
points at engine/Cargo.toml.
README: a Highlights section up top (unified install, Convert to FPKG,
sleep and wake), Android/web in the platforms badge, tested firmware 5.10 &
9.60.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>