Skip to content

release: 0.6.20 - #112

Merged
vibesoftwarecoder merged 1 commit into
masterfrom
release/0.6.20
Oct 13, 2026
Merged

vibesoftwarecoder merged 1 commit into
masterfrom
release/0.6.20

Conversation

@vibesoftwarecoder

Copy link
Copy Markdown
Owner

This release adds optional update notifications (off by default) and makes the source-build installer safe on a host whose install folder was once self-contained.

What was happening

scripts\install-service.ps1 built from source with dotnet publish straight into C:\Program Files\MultiSeat. dotnet publish copies MultiSeat.Service.runtimeconfig.json only when the source file is newer than the one already there. On a folder that had been self-contained, that left a hybrid: a framework-dependent runtimeconfig.json beside the old hostfxr.dll. The host then looked for a bundled runtime the config no longer declared, and the service failed to start with No frameworks were found (service control manager errors 7000 and 7009 after a 30 second timeout). It looked like a missing .NET runtime. The host had one installed.

The first publish onto such a folder could also pass by accident. The old self-contained config was newer, so it survived, and the new files ran on the leftover bundled runtime. Only a later publish broke it.

What changes

  • The source build no longer publishes into the install folder. It builds into a temporary staging folder (service, dashboard, InputHook DLL), checks it, and then uses the same routine -FromZip uses to replace the install folder as a whole.
  • The staged payload is checked before anything is touched: MultiSeat.Service.exe, appsettings.json, wwwroot\index.html, and a runtime layout that agrees with itself. A payload is consistent when hostfxr.dll is present exactly when runtimeconfig.json has includedFrameworks, and a framework-dependent payload carries no bundled runtime files. The installed folder gets the same check after the copy. A mismatch fails with the exact reason.
  • A source build checks the host's shared runtimes first. It reads the frameworks the built runtimeconfig.json demands (Microsoft.NETCore.App, Microsoft.AspNetCore.App) and compares them with the host's .NET install under the normal roll-forward rules. If one is missing, the installer stops before it stops the service, and says what to install or to use -FromZip instead.
  • The service is stopped only after that. If the copy fails, the installer puts the previous folder back from a full backup and starts the service again if it was running.
  • New backup: a full copy of the old install folder in C:\ProgramData\MultiSeat\install-backups\<timestamp>. The newest three are kept.
  • Both backup folders are now private. config-backups and install-backups hold copies of appsettings.local.json, which can carry the API key. They inherited ProgramData's permissions, so any standard user on the host could read them. They are now limited to SYSTEM, Administrators and the account that ran the installer. Existing config-backups from earlier installs are covered too.
  • Behaviour change for source builds: your appsettings.json and appsettings.local.json are now kept byte for byte, as -FromZip already did. A newer appsettings.json in the repo no longer replaces yours. Settings the build adds that your file lacks are listed during the install.
  • The "this release adds settings" list now works on Windows PowerShell 5.1. It could not parse the // comment lines in the shipped appsettings.json and printed the whole file as an error note instead.
  • The release asset check now also requires scripts\lib\install-lib.ps1, which the installer loads.

New: optional update notifications (off by default)

MultiSeat can now tell you on the dashboard when a newer MultiSeat, ApolloVibe or MoonlightVibe release exists. It is off unless you turn it on, because it is the first time the service would contact the internet. If you turn it on ("UpdateCheckEnabled": true in appsettings.local.json, or the switch on the System page), the service asks api.github.com for each project's release list about every 12 hours (UpdateCheckIntervalHours). It sends a generic User-Agent and nothing about your host. It never downloads or installs anything; it shows the release link, and you update by hand (see "Updating" in the README). Details: docs/security-posture.md, "Outbound connections". MoonlightVibe runs on your other devices, so MultiSeat cannot tell which version they have; it only shows the latest release.

If you upgrade with install-service.ps1 -FromZip, your existing appsettings.json is kept, so the new options are named by the installer and nothing changes until you opt in.

  • New endpoints, all behind the API key when authentication is on: GET /api/system/updates, POST /api/system/updates/check (at most once a minute) and POST /api/system/updates/settings.
  • Turning checks on or off, by file or from the dashboard, takes effect without a restart.
  • The last result is cached in C:\ProgramData\MultiSeat\update-check.json, readable only by SYSTEM and Administrators. It is safe to delete.

How this was checked

The installer, live. It was run for real on a host whose install folder was self-contained, which is exactly the situation that used to break the service. The source build staged the payload, verified it, checked the host's runtimes, stopped the service only after that, backed up the config files and the whole folder, replaced the folder, restored the config, and confirmed the installed folder is consistent. The service came back running, framework-dependent, with no hostfxr.dll left. The new backup folders were limited to SYSTEM, Administrators and the installing account, and the list of settings the build adds was printed correctly.

Update notifications, live. On the same host:

  • With checks off, the service held no connection outside the machine, sampled over ten seconds.
  • Turned on through the API, the change took effect without a restart. A check from the SYSTEM account reached GitHub over TLS in about a second. MultiSeat read as up to date, ApolloVibe was identified as 2026.6.1-ms6 by the SHA-256 of its sunshine.exe and read as up to date, and MoonlightVibe showed the latest release only, labelled as not tied to a client.
  • The scheduled check then ran on its own about every 12 hours for three days.
  • update-check.json was readable only by SYSTEM and Administrators and held no host name or user name.
  • Writing appsettings.local.json from the dashboard switch kept its access list and owner. Only the file's primary group field changed, which Windows does not use for access checks.

Tests. The full suite passes, and each new group was mutation-checked. The tests for timing-dependent code prove that the reader and writer overlapped instead of hoping they would, after one such test failed on a slow CI runner.

Not verified: a check behind a proxy, the failure and offline paths on a real network, the dashboard in a real browser (layout at phone width and the notices), and the settings switch on a host whose appsettings.local.json has a custom access list.

Known limitations

  • On at least one host the scale override is still ignored (issue FollowClientResolution doesn't carry the seat's scale override through a client-triggered reconnect #93): the dashboard shows "Running at 100%" beside the 200% that was asked for, with a note, and MultiSeat leaves the session alone. On the reference host the fix in 0.6.19 applies the scale correctly. We are working out what differs.
  • Seats capture the remote desktop surface, not a dedicated virtual display. A Windows constraint, not a regression.
  • The update check shows a MoonlightVibe release but cannot see which version your devices run.
  • A failed update check keeps showing an earlier "update available" notice and shows the error beside it.

Install

.\prerequisites\install-prerequisites.ps1     # drivers - needed either way
.\scripts\install-service.ps1 -FromZip .

Afterwards, confirm what landed:

& 'C:\Program Files\MultiSeat\MultiSeat.Service.exe' --config

It should report 0.6.20.


🤖 Generated with Claude Code

Bump version.txt and finish the 0.6.20 notes: drop the DRAFT block, record what was
verified live (the new installer on a self-contained folder; update notifications on
and off, with a real GitHub check from the SYSTEM account), and say plainly that one
reporter's host still ignores the scale override.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@vibesoftwarecoder
vibesoftwarecoder merged commit 0a3878c into master Oct 13, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant