<feed xmlns='http://www.w3.org/2005/Atom'>
<title>meshbay.git/packaging/win/service-mode.ps1, branch 0.16</title>
<subtitle>MeshBay — read-only public mirror</subtitle>
<id>https://git.meshbay.org/meshbay.git/atom?h=0.16</id>
<link rel='self' href='https://git.meshbay.org/meshbay.git/atom?h=0.16'/>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/'/>
<updated>2026-09-14T21:51:36Z</updated>
<entry>
<title>fix(win): a service-mode daemon can be replaced, and the Node page can link one</title>
<updated>2026-09-14T21:51:36Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-09-14T21:51:36Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=e12570f9d1aa2645e6bb223b1417fa0e81957b65'/>
<id>urn:sha1:e12570f9d1aa2645e6bb223b1417fa0e81957b65</id>
<content type='text'>
Two live-reproduced bugs in Windows node start/stop, found sideloading the
0.14.0 build:

- node:start's crash-recovery step killed a service-mode daemon with
  taskkill/CTRL_BREAK, both of which fail with "Access is denied" against a
  process running under the Scheduled Task's own S4U logon session (a
  different session from the Electron app's). The daemon it was meant to
  replace just kept running, unreplaced, and schtasks /run on a task Windows
  still considered Running was then a silent no-op too. Route through
  winServiceTaskEnd() (schtasks /end) first, the way nodeServiceStop/
  nodeServiceRestart already correctly do. service-mode.ps1 also now starts
  the task right after registering it -- Register-ScheduledTask's own
  AtStartup trigger does not run it immediately, so nothing was listening
  until the next reboot.

- The Node page's Start button called node.start() with no arguments, so an
  unlinked node (a fresh install, or one whose hub-side link was lost) could
  never link on Start alone -- only create-group-page.js's own call passed
  {hubUrl, username, token}. Reproduced on a fresh non-service install signed
  in to the real hub: Start hung for ~105s and failed with "could not link",
  pointing at a "Link Node" control that lives on Settings, not the Node
  page (that message is fixed too).

Co-Authored-By: Claude Sonnet 5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>feat: opt-in Windows service mode (boot-time, one elevation) + v1.0.0</title>
<updated>2026-09-04T15:29:24Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-09-04T15:29:24Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=b78288640d8c13cc0fb3f4ee7c82f3efac33940f'/>
<id>urn:sha1:b78288640d8c13cc0fb3f4ee7c82f3efac33940f</id>
<content type='text'>
The per-user Startup-folder launcher (W3) only ever runs after this user
signs in. A real Windows Service would start earlier, but under
LocalSystem/NetworkService -- accounts with no normal profile, so
%LOCALAPPDATA%\meshbay\ (config, keystore, data) would not exist for it.
Relocating storage to make that work is real surgery, deliberately not
done here.

Instead: a Scheduled Task, created once with admin rights, that runs AS
THIS USER at boot without needing them to sign in first.
`schtasks /create ... /ru &lt;user&gt; /rp ""` with no `/it` registers an S4U
(Service For User) logon -- no password stored anywhere, and unlike
LocalSystem it loads this account's own profile, so config_dir()/
data_dir() need zero changes. The cost: S4U carries no network credential,
which the node never needed -- everything it touches is local disk plus
outbound internet. Creating the task needs admin (a boot trigger touches
system-wide scheduler state, the same reason /sc onlogon needed it);
querying/starting/stopping an existing one does not -- Task Scheduler
grants the owning user that much itself, which is what lets the Node
page's Start/Stop/Restart drive it with no further UAC prompts.

meshbay_node/platform.py
  service_install/_remove/_status/_run/_end -- mirrors autostart_* but
  for the Scheduled Task; TASK_NAME moved here (was decorative before)

meshbay_node/daemon.py
  new `service install|remove|start|stop|status` verb; restart-daemon and
  reset now check for the service task too

packaging/win/service.ps1
  the installer-side equivalent (extraResource); status/run/end never
  self-elevate -- only install/remove do, exactly matching what
  Task Scheduler itself requires

packaging/win/service-mode.ps1
  ONE elevated helper running service.ps1 + firewall.ps1 together, so
  choosing service mode costs exactly one UAC prompt, not two

build/installer.nsh
  the install-time choice: "run as a background service?" (one
  elevation, both jobs) vs the existing per-user + separate firewall
  question. Checked first, unelevated, so re-running setup with
  everything already configured asks nothing. Uninstall offers the
  matching one-elevation cleanup, default No.

src/main.js
  winServiceTaskStatus/Run/End, wired into node:installed,
  node:service-status/-stop/-restart and node:start: when the Scheduled
  Task exists, drive it; otherwise fall back to the existing per-user
  spawn/kill path. This is the hard requirement -- Start/Stop/Restart
  from the Node page must work in either mode.

node-page.js / locales
  a hint explaining why the per-user autostart toggle is absent when
  service mode is active (info.mode from the backend, no new field to
  gate on -- it just isn't sent in that case)

package.json: 0.1.0 -&gt; 1.0.0.

Verified: electron-builder compiles the new NSIS choice logic and ships
all three scripts; service.ps1's S4U install fails cleanly (Access
denied) when run unelevated, and its status/run/end never touch "runas".
Cannot verify the elevated success path myself (no admin in this
session) -- that needs a real UAC click. Node suite 843 pass / 25 skip;
test_packaging_win.py pins the one-elevation property, the S4U flags,
and that main.js actually checks the service task in all three handlers.

Co-Authored-By: Claude Sonnet 5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
</feed>
