Skip to content

fix(desktop): restore profile/agent switching in release builds (nanostores 1.4.2) - #89690

Closed
royzhrxy-glitch wants to merge 1 commit into
NousResearch:mainfrom
royzhrxy-glitch:fix/desktop-nanostores-batch-drop
Closed

fix(desktop): restore profile/agent switching in release builds (nanostores 1.4.2)#89690
royzhrxy-glitch wants to merge 1 commit into
NousResearch:mainfrom
royzhrxy-glitch:fix/desktop-nanostores-batch-drop

Conversation

@royzhrxy-glitch

Copy link
Copy Markdown
Contributor

What does this PR do?

🔴 Critical production breakage: in packaged (minified) desktop builds, switching profiles or connection-scoped agents does nothing at all — clicking a profile in the rail is a silent no-op.

Root cause: nanostores 1.4.0–1.4.1 annotate batch() with /* @__NO_SIDE_EFFECTS__ */. Rollup (via vite build) honors that annotation and erases any result-unused batch(...) call as dead code — including its callback. Since d57f94a33 / 053eb7aab / 4e520f085 moved the gateway-switch publication (activate() + $activeGatewayProfile.set() + setConnection()) inside batch(() => { ... }), the entire publication is missing from release bundles:

// minified release bundle, before this fix:
let [e, n] = await Promise.all([la(t), Oi(t)])})().catch(...)   // <- nothing between await and catch

Dev builds and vitest run unminified, which is why this only shows up in the packaged app.

Fix: bump nanostores to 1.4.2, which removes the @__NO_SIDE_EFFECTS__ annotation from batch() (it remains on the creation functions like atom/computed, where it is correct). All three pinned copies are bumped (apps/desktop, apps/bootstrap-installer, ui-tui). No source changes to app code are needed.

A regression test (apps/desktop/src/store/nanostores-batch-guard.test.ts) asserts the installed nanostores never re-introduces a purity annotation on batch, so a future downgrade or re-annotation fails CI instead of silently shipping a dead profile switcher.

Related Issue

Fixes # — (no existing issue found; happy to file one if preferred)

Type of Change

  • 🐛 Bug fix (non-breaking change that fixes an issue)

Changes Made

  • apps/desktop/package.json, apps/bootstrap-installer/package.json, ui-tui/package.json: nanostores 1.4.01.4.2
  • package-lock.json: matching lock entries (surgical, no other churn)
  • apps/desktop/src/store/nanostores-batch-guard.test.ts (new): regression guard against the annotation returning

How to Test

  1. cd apps/desktop && npm ci && npm run build — then inspect the minified bundle: the gateway-switch publication survives (s(() => { n() && (X.set(t), e && Jt(e)) }) now present after the Promise.all in the profile chunk; previously the block was erased entirely).
  2. npx vitest run src/store/ — all 37 tests pass, including the atomic-publication tests from 4e520f085 and the new guard test.
  3. Packaged app end-to-end (Linux, Wayland): built with npm run pack, launched release/linux-unpacked/Hermes, pressed Ctrl+Shift+] twice — active profile cycled cetcworker → hermes-wsl → quantify and the sidebar session list followed each switch. Before the fix the same steps were a no-op.

Checklist

Code

  • I've read the Contributing Guide
  • My commit messages follow Conventional Commits (fix(scope):, feat(scope):, etc.)
  • I searched for existing PRs to make sure this isn't a duplicate
  • My PR contains only changes related to this fix/feature (no unrelated commits)
  • I've run pytest tests/ -q and all tests pass — N/A (desktop TS change only; ran the desktop vitest suite instead: 37/37 pass)
  • I've added tests for my changes (required for bug fixes, strongly encouraged for features)
  • I've tested on my platform: Ubuntu 24.04 (Wayland, GNOME fractional scaling), Electron 40.10.2

Documentation & Housekeeping

  • I've updated relevant documentation (README, docs/, docstrings) — N/A
  • I've updated cli-config.yaml.example if I added/changed config keys — N/A
  • I've updated CONTRIBUTING.md or AGENTS.md if I changed architecture or workflows — N/A
  • I've considered cross-platform impact (Windows, macOS) per the compatibility guide — the bug is platform-independent (build-time treeshaking), and the fix is a patch-level dependency bump
  • I've updated tool descriptions/schemas if I changed tool behavior — N/A

Screenshots / Logs

Verification log from the packaged Linux build (keyboard profile cycling; before the fix this produced no state change):

active before: cetcworker | top session: 开发体系 #29
active after next: hermes-wsl | top session: 自由空间 #7
active after next#2: quantify | top session: 量化主进程

…stores 1.4.2)

nanostores 1.4.0-1.4.1 annotate batch() @__NO_SIDE_EFFECTS__. Rollup
(via vite build) honors that and erases a result-unused batch(...) call
as dead code -- callback included. Since d57f94a/053eb7aab/4e520f085
moved the gateway-switch publication (activate() +
+ ) inside batch(), packaged desktop builds lost the entire
publication: clicking a profile in the rail did nothing at all.

Dev builds and vitest run unminified, so only the packaged app broke.

nanostores 1.4.2 removes the annotation from batch() (it stays on the
creation functions, where it is correct). Bump all three pinned copies
(apps/desktop, apps/bootstrap-installer, ui-tui) and add a regression
test asserting the installed nanostores never re-annotates batch.
@royzhrxy-glitch
royzhrxy-glitch requested a review from a team August 19, 2026 03:32
@alt-glitch alt-glitch added type/bug Something isn't working P2 Medium — degraded but workaround exists comp/desktop Electron desktop app (apps/desktop/*) comp/tui Terminal UI (ui-tui/ + tui_gateway/) area/profiles Multi-profile isolation, HERMES_HOME scoping sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state labels Aug 19, 2026
@frizikk

frizikk commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

I independently reproduced this release-build failure on current main.

The remote gateway was healthy and reachable, OAuth session validation and WebSocket ticket issuance succeeded, and the profile-scoped WebSocket connected successfully. Despite that, the Desktop connection remained on the previous target and the switch ended with the generic “did not become active” error.

Instrumenting the switch path showed that the target descriptor resolved correctly, but the production bundle omitted the entire callback passed to batch(), including the activation and connection publication. The installed nanostores@1.4.0 contains the @__NO_SIDE_EFFECTS__ annotation immediately before batch, matching the root cause described here.

This is therefore independently confirmed as a production tree-shaking regression rather than a gateway, authentication, or profile-discovery failure.

@frizikk

frizikk commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

One additional cross-PR note: #89797 is complementary rather than a replacement for this change.

#89797 fixes the mid-dial pruning race and introduces atomic profile/connection publication, but its current head still pins nanostores@1.4.0 and places that publication inside batch(). Without this dependency update, production tree-shaking can still remove the callback.

For the complete fix, both changes are needed: #89797 for reliable activation under pruning, and this PR for preserving the publication transaction in packaged builds.

@teknium1

Copy link
Copy Markdown
Contributor

Merged via #89875 with your commit cherry-picked and authorship preserved — thank you for an outstanding find. Diagnosing this from a minified bundle diff was exactly the evidence that settled it: we reproduced the @__NO_SIDE_EFFECTS__ DCE in an isolated A/B (1.4.0 erases the batched publication from the bundle; 1.4.2 keeps it), confirmed it in our own build artifacts, and live-verified the bumped minified build in the Electron app. Your annotation-guard regression test rode along unchanged. This also retroactively explained the root cause of the #89622 breakage window. Closing since the salvage PR has landed on main.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/profiles Multi-profile isolation, HERMES_HOME scoping comp/desktop Electron desktop app (apps/desktop/*) comp/tui Terminal UI (ui-tui/ + tui_gateway/) P2 Medium — degraded but workaround exists sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants