<feed xmlns='http://www.w3.org/2005/Atom'>
<title>meshbay.git/packages/meshbay-client/build, branch 0.20</title>
<subtitle>MeshBay — read-only public mirror</subtitle>
<id>https://git.meshbay.org/meshbay.git/atom?h=0.20</id>
<link rel='self' href='https://git.meshbay.org/meshbay.git/atom?h=0.20'/>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/'/>
<updated>2026-10-15T15:45:41Z</updated>
<entry>
<title>fix(packaging): setup ends a command-line client run from its install</title>
<updated>2026-10-15T15:45:41Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-10-15T15:42:30Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=0d082ab4d19412079516b281aff76e8c3f70d9ba'/>
<id>urn:sha1:0d082ab4d19412079516b281aff76e8c3f70d9ba</id>
<content type='text'>
A `meshbay-cli chat --follow` left open holds node-runtime's DLLs, so the
previous version's uninstaller failed ("Failed to uninstall old application
files"), a silent update included, and left the node it had stopped not
running. stop-node.ps1 now ends a meshbay-cli.exe run from this install
(-InstallDir, setup's $INSTDIR), and no other copy.

Found through CIM, not Get-Process: setup runs the 32-bit PowerShell, which
reads no path for a 64-bit process, and the first version of the stop matched
nothing. The test runs the script in that PowerShell. Checked live: an update
over a running follower now ends it, replaces every file and restarts the node.

Co-Authored-By: Claude Opus 5.5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>feat(cli): meshbay-cli, a command-line client for members</title>
<updated>2026-10-14T20:20:15Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-10-14T20:20:15Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=422647e7898b8df67cd11f8fb060aec23dec84aa'/>
<id>urn:sha1:422647e7898b8df67cd11f8fb060aec23dec84aa</id>
<content type='text'>
Signs in to the hub, lists the account's groups and their folders, and
downloads and uploads files directly with each group's node, end-to-end
encrypted. With no argument it opens a two-pane interactive mode (Textual).
Session and device keys are kept encrypted under the system's key storage,
or a 0600 key file where there is none; node keys are pinned at first
contact; a new machine links as a device.

Packaged on its own on Linux (deb and rpm, on meshbay-common's venv, with a
man page generated from the parser) and frozen next to meshbay-node in the
full Windows installer, not the light one, with a self-test the build runs.
client/keys.py ports keyderive.js and is LGPL like it.

Co-Authored-By: Claude Opus 5.5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>feat(packaging): the Store package declares what the NSIS scripts do</title>
<updated>2026-10-10T07:57:29Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-10-09T16:19:06Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=42b562fcf312ddceb78438b5daea49d4c9b465c8'/>
<id>urn:sha1:42b562fcf312ddceb78438b5daea49d4c9b465c8</id>
<content type='text'>
A test-signed install of the MSIX build, in the WindowsApps folder a Store
install uses, showed that every script-made piece of the NSIS model breaks
there, because each names the install folder and every update deletes it:
the firewall rules went stale, the PATH entries piled up pointing at deleted
folders, and the Startup-folder .vbs was refused ("Permission denied") right
after sign-in. The network capabilities the manifest declared covered
nothing: they make rules for sandboxed apps only, and a listener in the
package still got the Windows firewall prompt. The package's own startup
task was on by default, started the node whatever mode the Node page said,
and ran the console executable, whose window stopped the node when closed.

The package now declares what Windows then creates at install, carries
across updates and removes with the app, all without an administrator
prompt (each measured on the real install, through an update and a reboot):

- firewall rules for the node, in a custom manifest template, since only a
  package-level element can hold them;
- the startup task, off by default, running meshbay-nodew.exe, a new build
  of the daemon without a console;
- an execution alias for meshbay-node.exe, so the app adds no PATH entry.

The node's CLI switches the startup task (platform.startup_task, ctypes over
the WinRT ABI): Windows gives the package's identity to the executables in
it, not to a powershell.exe the app starts, which got "Element not found".
`meshbay-node autostart install | remove | status` therefore works in the
Store package from the app and a terminal alike; the app caches the answer,
since the Node page polls. Starting at boot stays the .exe installer's: the
Store package offers no service mode, and the CLI refuses `service install`
there. Process listings count both image names.

The Node page's status poll cleared the message of a refused action within
five seconds; the two errors are kept apart now (all Windows builds).

Co-Authored-By: Claude Opus 5.5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>fix(client): remove firewall rules and boot task on uninstall, unasked</title>
<updated>2026-10-07T11:48:28Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-10-07T11:48:28Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=ade41b05cce4a555197116568664220c5b3be9fa'/>
<id>urn:sha1:ade41b05cce4a555197116568664220c5b3be9fa</id>
<content type='text'>
The Yes/No before it defaulted to No, so they stayed behind. Read both
unelevated and raise the UAC prompt only when one is left.

Co-Authored-By: Claude Opus 5.5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>fix: Windows installer and desktop app start and stop the node one way</title>
<updated>2026-09-27T20:20:53Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-09-27T20:20:53Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=8c7e39b6dca758badec6867ab6610fd5e8d93d1e'/>
<id>urn:sha1:8c7e39b6dca758badec6867ab6610fd5e8d93d1e</id>
<content type='text'>
A 0.16 upgrade in service mode left the previous node running: setup's
unelevated taskkill cannot reach session 0, and it ran in customInstall, which
electron-builder inserts after the files are copied. The locked exe was not
replaced, and the new app talked to the old node ("started but could not link",
"No operator paired").

Installer (build/installer.nsh, build/stop-node.ps1):
- customCheckAppRunning, which runs before uninstallOldVersion and extraction,
  stops the node with an embedded stop-node.ps1: control API, then schtasks
  /end, then Stop-Process, and refuses to half-upgrade if one survives.
- An upgrade keeps the mode it finds (task, launcher, previous install),
  restores the sign-in launcher the old uninstaller deletes, and restarts the
  node the way that mode runs it. A silent upgrade of an "at sign-in" install
  used to end with no autostart and no node.
- The uninstaller removes the task and firewall rules only on a real
  uninstall, not on an update.

Desktop app (src/main.js):
- Start, Stop, Restart and node:start go through the CLI's lifecycle verbs
  instead of a second implementation; a child spawned by Electron also held
  Electron's sockets after the app quit.
- "Only while MeshBay is open" is a real mode: the app starts a provisioned
  node at launch and stops the one it started when it quits.
- Switching modes stops the node first -- deleting a task does not end its
  instance, and a new service found the port taken -- keeps the firewall
  rules every mode needs, and starts the node again. A declined or unanswered
  UAC prompt restores the node instead of leaving it stopped, and says that
  nothing changed.
- waiting_for_hub counts as a node that is up; linking waits for a node that
  answers, with a longer deadline, and reports a version mismatch.

Packaging (packaging/win):
- The service task gets no 72-hour limit, runs on battery and ignores a second
  start; service.ps1 status reports a stale registration so setup re-registers
  it; remove ends the running instance before deleting the task.
- build-node-runtime.ps1 starts the frozen daemon in a throwaway profile
  (smoke-node-runtime.ps1) instead of only asking for --help.

The mode that was "Off (start manually)" is labelled "Only while MeshBay is
open" in all ten catalogues.

Co-Authored-By: Claude Opus 5.5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>feat(packaging): an MSIX target for Microsoft Store submission</title>
<updated>2026-09-11T15:51:51Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-09-11T15:47:42Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=edbff1768054afa80efda721cd1011b29c7fe355'/>
<id>urn:sha1:edbff1768054afa80efda721cd1011b29c7fe355</id>
<content type='text'>
Store certification of the NSIS "MSI/EXE" submission failed on three
checks (silent-install verification, Add/Remove Programs entry, bundleware
check) -- traced and reproduced live to one cause: SmartScreen blocks an
unsigned, internet-downloaded installer at the shell layer before
Microsoft's own unattended validation bot ever gets to run it. MSIX
sidesteps this class of failure entirely: submitted through the Store's
native pipeline, there is no browser-download-then-launch step for
SmartScreen to intercept, and Microsoft signs the package itself at
publish time -- free, and specific to this submission type (Trusted
Signing remains a paid service for the MSI/EXE path). Full plan and
findings: C:\Users\admin\devel\msix-installer.md (out of repo).

electron-builder.msix.yml carries the same bundle as Full (node runtime,
ffmpeg, both service scripts) -- an AppX/MSIX install never elevates, by
design, but that changes only *when* the two elevated operations can run,
not whether the daemon ships. No main.js changes were needed: the on-demand
elevation path for service-mode (winElevateServiceMode(), driven from the
Node page) already existed for a different reason and depends only on
service-mode.ps1 being present as an extraResource, true for any packaged
Windows target. identityName/publisher/publisherDisplayName are the real
values from Partner Center's app-identity reservation, not placeholders.

build-win-msix.ps1 points electron-builder at the system Windows 10 SDK
(auto-detected) instead of letting it download its own bundled copy --
that download's 7z extraction creates symlinks this target never uses and
fails without SeCreateSymbolicLinkPrivilege, reproduced on this machine.
build/appx/ carries the four tile images the AppX target requires
regardless of showNameOnTiles, generated once from the existing app icon
(see that directory's README) since the system-SDK redirect has no vendor
samples to fall back to. build/appx-extensions.xml declares
windows.startupTask by hand rather than via electron-builder's
addAutoLaunchExtension, which always targets the Electron shell -- this
points at the bundled node binary instead, matching what "starts at sign
in" already means for Full.

Verified live via a signed sideload install (self-signed test cert,
cleaned up after): the package installs and the app runs correctly. One
finding worth carrying forward -- the declared network capabilities
(internetClientServer, privateNetworkClientServer) do not create any
firewall exemption for this app, most likely because automatic
capability-based exemption is an AppContainer-sandbox property and this
app deliberately runs full-trust, outside any sandbox. Not a regression:
no install-time elevation was possible either way, so the cost is the same
one-time OS firewall prompt firewall.ps1's own header already documents as
its fallback today.

Co-Authored-By: Claude Sonnet 5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>feat(packaging): a Light installer target with no bundled node runtime</title>
<updated>2026-09-11T15:51:51Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-09-11T12:17:50Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=bca6fc3f0884fcdb0455b502ee4495b04945baee'/>
<id>urn:sha1:bca6fc3f0884fcdb0455b502ee4495b04945baee</id>
<content type='text'>
MeshBay Light ships the Electron client + UI only -- no PyInstaller node
freeze, no ffmpeg, no service install/autostart. Two standalone
electron-builder configs (Full via package.json's build field, Light via
electron-builder.light.yml passed with --config, which reads only that
file -- confirmed against app-builder-lib's own config loader) rather than
one config branching on a flag.

build-win-common.ps1 holds the steps both orchestrators share (Node check,
npm ci, Electron bump, sync-ui) so build-win.ps1 (Full) and the new
build-win-light.ps1 cannot drift apart; build-win.ps1 is refactored to
dot-source it with no behavior change (rebuilt and diffed byte-identical
output).

installer-light.nsh keeps the one thing Light still needs -- an
unconditional firewall rule, since the client listens too -- and none of
the service-mode/autostart machinery installer.nsh carries, which has
nothing to gate without a bundled node.

dist-light/ (Light's own electron-builder output dir) gets its own
.gitignore line since the bare dist/ rule does not match it.

Co-Authored-By: Claude Sonnet 5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>feat(packaging): one radio page for Windows autostart, firewall every mode</title>
<updated>2026-09-10T23:33:05Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-09-10T23:33:05Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=e0607a9cee6ce9596e775baaed43eb67e1e5a293'/>
<id>urn:sha1:e0607a9cee6ce9596e775baaed43eb67e1e5a293</id>
<content type='text'>
Operator feedback on the 0.13.0 installer:

- The all-users / current-user page (electron-builder's PAGE_INSTALL_MODE)
  only ever showed "anyone who uses this computer" disabled -- MeshBay is
  per-user only (account-bound keystore/DPAPI, MESHBAY_DESIGN.md 11.2) and
  build.nsis forbids elevation. customInstallMode forces $isForceCurrentInstall
  so the page is skipped.

- The two nested Yes/No MessageBoxes are one nsDialogs radio page
  (customPageAfterChangeDir): only-while-open / at-sign-in / background service,
  default background service. customInit seeds MB_AutoMode "2" for silent
  installs where the page never runs. "At sign-in" now writes the Startup .vbs
  from the installer (meshbay-node autostart install, unelevated); the old
  per-user branch set up nothing.

- The firewall rules go in for every mode, not behind a second opt-in -- a node
  that accepts no connections is the failure mode MESHBAY_DESIGN.md 7.5 names.
  Folded into the service elevation for mode 2; their own single elevation for
  0/1. Unelevated short-circuit kept but narrower: firewall.ps1 check AND
  service.ps1 status must both pass to skip mode 2's UAC.

Var MB_AutoMode lives inside customPageAfterChangeDir, not at file scope: the
uninstaller compile pass inserts none of the macros that read it and
makensis -WX turns "unused Var" (6001) into a hard error.

Not yet exercised on a real machine -- the NSIS UI cannot be driven from the
build env. test_packaging_win.py pins the script shape.

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>
<entry>
<title>fix(packaging): re-running setup no longer re-prompts for firewall access</title>
<updated>2026-09-04T14:08:06Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-09-04T14:08:06Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=a4aabd1d33770d6199a8cb7bc87f639668617bc9'/>
<id>urn:sha1:a4aabd1d33770d6199a8cb7bc87f639668617bc9</id>
<content type='text'>
Every run of customInstall showed the "Allow MeshBay through Windows
Firewall?" question and, on Yes, a fresh UAC prompt -- an upgrade or repair
install would ask again even with all four rules already in place.

customInstall now checks first: firewall.ps1 check, unelevated
(Get-NetFirewallRule needs no admin, only New/Remove do), exits 0 if every
rule already exists. Only a nonzero result reaches the MessageBox and the
elevated add. A second run of setup on an already-configured machine now
asks nothing.

Verified unelevated: check exits 1 and logs which rules are missing on a
machine with none of them (the fresh-install case); electron-builder
compiles the nsExec::Exec / Pop $0 / ${If} wiring. Node suite 837 pass /
25 skip.

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