aboutsummaryrefslogtreecommitdiffstats
path: root/packaging/win/ensure-node-path.ps1
diff options
context:
space:
mode:
authorChristophe Besson <cbesson@gmail.com>2026-09-12 15:48:03 +0200
committerChristophe Besson <cbesson@gmail.com>2026-09-12 15:48:22 +0200
commit9cc2909cb4a360c81b471ceab1d9578a7655a88e (patch)
treeda6da7ff43eed10382e72247ef7c84b142a42ca5 /packaging/win/ensure-node-path.ps1
parentd8885c8df17c60927cb8d1f77ce1745814c6d3b4 (diff)
downloadmeshbay-9cc2909cb4a360c81b471ceab1d9578a7655a88e.tar.gz
fix(packaging): three MSIX first-run regressions found by a real sideload
A second-machine sideload of the MSIX target surfaced three things the earlier verification round (which only proved the package installs and runs) had missed: 1. meshbay-node missing from PATH. installer.nsh's customInstall adds node-runtime\ to HKCU\Environment at install time -- an unelevated per-user write, never blocked by MSIX's no-elevation rule, only by the more basic fact that an AppX/MSIX install runs no custom code at all. packaging/win/ensure-node-path.ps1 (idempotent, no admin verb) plus main.js's winEnsureNodeOnPath() do it from the app itself instead, once per launch, shipped to Full and MSIX (not Light, nothing to add there). Verified live via the Node inspector protocol: the entry was in HKCU\Environment\Path after a launch, absent before. 2. A daemon that crashes on startup failed silently. spawnNodeDetached() used stdio: 'ignore', so a real crash reproduced live (a second instance colliding with the first on 127.0.0.1:18000) left waitForNode()'s generic 60s timeout as the only failure ever shown. spawnNodeDetachedWatched() pipes stdio and watches ~2.5s, rejecting immediately with the daemon's own stderr on an early exit; a survivor has its streams released and runs fully detached exactly as before. First version bounded the captured text by line count and a live test showed that cut the actual OSError line -- two uvicorn/asyncio tracebacks followed it in the real capture -- so it is bounded by characters instead. 3. No hint that a startup-mode choice exists. The install-time radio page was the only place this was ever offered, and nothing replaces it now that no install-time page can exist at all. SetupWelcome (the existing first-run banner) grew a conditional hint, shown only while a bundled node is present and neither autostart nor service mode is configured yet. Considered and rejected: linking straight to the Node page -- its route is gated on a linked hub node key, false on the exact fresh-install screen this hint targets, so the link would have been dead on arrival. New key setup.node_startup_hint, added to all ten locale catalogues. test_packaging_win.py gained six tests pinning all three (69 total). Full plan and verification detail: C:\Users\admin\devel\msix-installer.md section 13 (out of repo). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Diffstat (limited to 'packaging/win/ensure-node-path.ps1')
-rw-r--r--packaging/win/ensure-node-path.ps160
1 files changed, 60 insertions, 0 deletions
diff --git a/packaging/win/ensure-node-path.ps1 b/packaging/win/ensure-node-path.ps1
new file mode 100644
index 0000000..f9b6f68
--- /dev/null
+++ b/packaging/win/ensure-node-path.ps1
@@ -0,0 +1,60 @@
+<#
+.SYNOPSIS
+ Add the bundled node-runtime directory to the per-user PATH, if it is not
+ there already.
+
+.DESCRIPTION
+ build/installer.nsh's customInstall does this at install time for the NSIS
+ Full target (HKCU\Environment, no elevation -- a per-user registry write
+ needs none). An AppX/MSIX install has no install-time hook at all, elevated
+ or not -- not a signing/elevation gap like the firewall rule or
+ service-mode, but the more basic fact that MSIX runs no custom code
+ whatsoever during setup. So the MSIX target calls this itself, once, on
+ first launch (main.js's winEnsureNodeOnPath()) instead.
+
+ Idempotent and safe to run on every launch of any packaged Windows build,
+ NSIS Full included: if the installer already added the entry, this is a
+ fast no-op query. Never touches PATH for a Light install (no bundled
+ node-runtime to add) -- the caller only invokes this when
+ hasBundledNode() is true.
+
+ Broadcasts WM_SETTINGCHANGE afterward so already-open shells notice --
+ same as the installer's own SendMessage call. New shells pick it up
+ either way.
+
+.PARAMETER NodeDir
+ Full path to the node-runtime directory to add.
+#>
+[CmdletBinding()]
+param(
+ [Parameter(Mandatory = $true)][string]$NodeDir
+)
+
+$ErrorActionPreference = "Stop"
+
+$key = "Registry::HKEY_CURRENT_USER\Environment"
+$current = (Get-ItemProperty -Path $key -Name "Path" -ErrorAction SilentlyContinue).Path
+if ($null -eq $current) { $current = "" }
+
+$parts = $current -split ";" | Where-Object { $_ -ne "" }
+$already = $parts | Where-Object { $_.TrimEnd('\') -ieq $NodeDir.TrimEnd('\') }
+if ($already) {
+ Write-Output "already present"
+ exit 0
+}
+
+$next = if ($parts.Count -gt 0) { ($parts + $NodeDir) -join ";" } else { $NodeDir }
+# ExpandString, not String -- matches installer.nsh's WriteRegExpandStr, so any
+# %VAR% another entry already carries on this machine keeps expanding.
+New-ItemProperty -Path $key -Name "Path" -Value $next -PropertyType ExpandString -Force | Out-Null
+
+Add-Type -Namespace MeshBay -Name NativeMethods -MemberDefinition @"
+ [System.Runtime.InteropServices.DllImport("user32.dll", SetLastError = true, CharSet = System.Runtime.InteropServices.CharSet.Auto)]
+ public static extern System.IntPtr SendMessageTimeout(System.IntPtr hWnd, uint Msg, System.UIntPtr wParam, string lParam, uint fuFlags, uint uTimeout, out System.UIntPtr lpdwResult);
+"@
+$HWND_BROADCAST = [IntPtr]0xffff
+$WM_SETTINGCHANGE = 0x1a
+$result = [UIntPtr]::Zero
+[MeshBay.NativeMethods]::SendMessageTimeout($HWND_BROADCAST, $WM_SETTINGCHANGE, [UIntPtr]::Zero, "Environment", 2, 5000, [ref]$result) | Out-Null
+
+Write-Output "added"