Two fixes addressing review feedback on the previous avalonia-gui PR round.
1. Platform filter was using host OS (`IsWindows() ? "windows" : "linux"`),
which dropped all `platform=windows` manifest entries whenever the
launcher ran on Linux. Since the client is always a Windows PE binary
launched through Wine on Linux hosts, the target platform we apply is
always `"windows"` regardless of host. Before this, the orchestrator
silently skipped Metin2.exe and the python314 / openssl / mingw runtime
DLLs on Linux, leaving an unbootable install dir.
2. Added `PruneStaleFiles` that walks clientRoot after every successful
update (both the normal apply path and the already-up-to-date
short-circuit) and deletes any file not in the manifest. Without it,
switching from a dirty release to a leaner one — e.g. dropping legacy
.pck after a .m2p migration — left orphaned files on disk and inflated
the install dir.
The keep set is `manifest.files ∪ {manifest.launcher.path}`. Per the
manifest spec in `m2dev-client/docs/update-manifest.md`, the top-level
launcher entry is privileged and never listed in files; it must
survive prune so a correctly-authored manifest does not delete the
updater itself (caught in Jakub's review of the previous round).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
UpdateOrchestrator now resolves an IReleaseFormat from the verified
manifest and uses it to filter applicable files, run the post-apply
hook (which loads the m2pack runtime key when present) and drive the
opt-in client-applied telemetry ping. GameProcess.BuildStartInfo
accepts a RuntimeKey? and forwards it through EnvVarKeyDelivery onto
the child ProcessStartInfo, scoped to the child environment only.
Program.cs wires the reporter and threads the key from the update
result into the game launch.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Lifts the manifest fetch / verify / diff / download / apply pipeline out
of Program.cs into a reusable UpdateOrchestrator that emits typed
LauncherState progress events through IProgress<UpdateProgress>. The
existing logic, error handling, and signature-failure semantics are
preserved verbatim; the orchestrator just drives a sink instead of the
console so the GUI and the headless --nogui path can share one pipeline.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>