{
  "id": "mesh-client",
  "name": "mesh-client",
  "kind": "client",
  "status": "active",
  "maturity": "stable",
  "description": "Cross-platform Electron desktop client for Meshtastic, MeshCore and Reticulum (LXMF) on macOS, Linux and Windows. Supports BLE, USB serial, Wi-Fi/TCP and MQTT; keeps local SQLite history, routing diagnostics, 16-language UI, TAK CoT gateway, PKI remote admin, mapping, telemetry and automated CI releases.",
  "maintainers": [
    {
      "name": "Colorado Mesh",
      "url": "https://github.com/Colorado-Mesh"
    }
  ],
  "repository": "https://github.com/Colorado-Mesh/mesh-client",
  "website": "https://colorado-mesh.github.io/mesh-client/",
  "license": "MIT",
  "languages": [
    "typescript"
  ],
  "screenshots": [
    {
      "file": "nodes.png",
      "caption": "Node list with signal bars and health scores"
    },
    {
      "file": "map.png",
      "caption": "Interactive map with position trails and layers"
    },
    {
      "file": "diagnostics.png",
      "caption": "Routing diagnostics and mesh health panel"
    },
    {
      "file": "chat.png",
      "caption": "Channel chat with delivery and transport badges"
    }
  ],
  "platforms": [
    "linux",
    "macos",
    "windows"
  ],
  "interfaces": [
    "gui"
  ],
  "connections": [
    "ble",
    "serial",
    "usb",
    "tcp",
    "mqtt"
  ],
  "node_roles": [
    "companion",
    "repeater",
    "room-server"
  ],
  "capabilities": [
    "messaging",
    "contacts",
    "channels",
    "node-configuration",
    "remote-administration",
    "monitoring",
    "telemetry",
    "packet-analysis",
    "mapping",
    "firmware-update",
    "automation",
    "notifications",
    "bridging",
    "key-management"
  ],
  "install": [
    {
      "type": "github-release",
      "url": "https://github.com/Colorado-Mesh/mesh-client/releases"
    },
    {
      "type": "source",
      "url": "https://github.com/Colorado-Mesh/mesh-client"
    }
  ],
  "popularity": {
    "githubStars": 75,
    "githubForks": 9,
    "githubWatchers": 1,
    "githubOpenIssues": 7,
    "githubContributors": 7,
    "lastChecked": "2026-07-21",
    "releaseDownloads": 18729,
    "latestReleaseDownloads": 82
  },
  "verification": {
    "sourceAvailable": true,
    "releasesAvailable": true,
    "signedReleases": false,
    "ciBuilds": true,
    "hasDocumentation": true,
    "lastChecked": "2026-07-21",
    "notes": [
      "README lists screenshots in docs/images/; no local screenshots downloaded yet.",
      "Multi-protocol client; supports Meshtastic, MeshCore and Reticulum via an AGPL Rust sidecar."
    ]
  },
  "tags": [
    "electron",
    "desktop",
    "cross-platform",
    "multi-protocol",
    "meshtastic",
    "reticulum"
  ],
  "last_reviewed": "2026-07-03",
  "source": {
    "path": "data/software/mesh-client/software.yaml",
    "updatedAt": "2026-07-21T08:04:18Z"
  },
  "latest_version": "5.24.1",
  "released": "2026-07-21",
  "releases": [
    {
      "version": "v5.24.1",
      "name": "5.24.1",
      "datetime": "2026-07-21T00:06:52Z",
      "url": "https://github.com/Colorado-Mesh/mesh-client/releases/tag/v5.24.1",
      "prerelease": false,
      "notes": "## [v5.24.1] - 2026-07-20\r\n\r\n### Highlights\r\n- MeshCore repeater admin: paginated Neighbors with Load more, clearer disconnect toasts, and safer CLI quick commands.\r\n- Reticulum RNode: Wi‑Fi TCP keepalive so idle links stop dropping around ~6s, plus clearer macOS BLE pairing (in-panel PIN, 60s passkey window, less reconnect thrash).\r\n\r\n### What's Changed\r\n\r\n### Features\r\n- **MeshCore repeater admin** — Paginated Neighbors with Load more (Repeaters panel + node detail), disconnect toasts for Status/Telemetry/Neighbors, and safer CLI quick pills (`clock`, `clock sync`, `clear stats`, `advert`, `board`) ([#697](https://github.com/Colorado-Mesh/mesh-client/pull/697))\r\n\r\n### Bug Fixes\r\n- **Reticulum RNode TCP keepalive** — Overlay rsReticulum activity keepalive so Wi‑Fi RNodes do not idle-FIN around ~6s ([#698](https://github.com/Colorado-Mesh/mesh-client/pull/698))\r\n- **macOS BLE RNode pairing UX** — Surface Admin Start pairing PIN in-panel (never Meshtastic `123456`), extend connect grace/hints to ~60s for the OS passkey window, latch `blePairingTimedOut` into Connection + Diagnostics, and debounce pairing-transition reconnect thrash ([#698](https://github.com/Colorado-Mesh/mesh-client/pull/698))\r\n- **Meshtastic node delete** — Wire Node Detail Confirm delete to the Meshtastic runtime so the button actually removes the node ([#695](https://github.com/Colorado-Mesh/mesh-client/pull/695))\r\n- **Meshtastic disconnect teardown** — Abort inbound `fromDevice` pipe before awaiting `toDevice.close`, tolerate abrupt writable close errors, and reduce reconnect flakiness after serial/BLE disconnect ([#693](https://github.com/Colorado-Mesh/mesh-client/pull/693))\r\n\r\n### Other Changes\r\n- **Faster pre-commit** — Staged-related Vitest (`test:staged`), staged ESLint with cache, and path-gated `check:*` scanners; PR CI and `pnpm run release` still run the full suite ([#696](https://github.com/Colorado-Mesh/mesh-client/pull/696))\r\n- **Patches / deps** — Track upstream patch PRs in `patches/README.md` and Ratspeak overlay registry; sync `usb` MSVC C++17 build flags; routine dependency bumps ([#693](https://github.com/Colorado-Mesh/mesh-client/pull/693), [#694](https://github.com/Colorado-Mesh/mesh-client/pull/694))\r\n\r\n### Breaking Changes\r\n\r\n*(None)*\r\n\r\n### Full Changelog\r\n\r\n[`v5.24.0...v5.24.1`](https://github.com/Colorado-Mesh/mesh-client/compare/v5.24.0...v5.24.1)",
      "notesHtml": "<h2>[v5.24.1] - 2026-07-20</h2>\n<h3>Highlights</h3>\n<ul>\n<li>MeshCore repeater admin: paginated Neighbors with Load more, clearer disconnect toasts, and safer CLI quick commands.</li>\n<li>Reticulum RNode: Wi‑Fi TCP keepalive so idle links stop dropping around ~6s, plus clearer macOS BLE pairing (in-panel PIN, 60s passkey window, less reconnect thrash).</li>\n</ul>\n<h3>What's Changed</h3>\n<h3>Features</h3>\n<ul>\n<li><strong>MeshCore repeater admin</strong> — Paginated Neighbors with Load more (Repeaters panel + node detail), disconnect toasts for Status/Telemetry/Neighbors, and safer CLI quick pills (<code>clock</code>, <code>clock sync</code>, <code>clear stats</code>, <code>advert</code>, <code>board</code>) (<a href=\"https://github.com/Colorado-Mesh/mesh-client/pull/697\" target=\"_blank\" rel=\"noopener noreferrer\">#697</a>)</li>\n</ul>\n<h3>Bug Fixes</h3>\n<ul>\n<li><strong>Reticulum RNode TCP keepalive</strong> — Overlay rsReticulum activity keepalive so Wi‑Fi RNodes do not idle-FIN around ~6s (<a href=\"https://github.com/Colorado-Mesh/mesh-client/pull/698\" target=\"_blank\" rel=\"noopener noreferrer\">#698</a>)</li>\n<li><strong>macOS BLE RNode pairing UX</strong> — Surface Admin Start pairing PIN in-panel (never Meshtastic <code>123456</code>), extend connect grace/hints to ~60s for the OS passkey window, latch <code>blePairingTimedOut</code> into Connection + Diagnostics, and debounce pairing-transition reconnect thrash (<a href=\"https://github.com/Colorado-Mesh/mesh-client/pull/698\" target=\"_blank\" rel=\"noopener noreferrer\">#698</a>)</li>\n<li><strong>Meshtastic node delete</strong> — Wire Node Detail Confirm delete to the Meshtastic runtime so the button actually removes the node (<a href=\"https://github.com/Colorado-Mesh/mesh-client/pull/695\" target=\"_blank\" rel=\"noopener noreferrer\">#695</a>)</li>\n<li><strong>Meshtastic disconnect teardown</strong> — Abort inbound <code>fromDevice</code> pipe before awaiting <code>toDevice.close</code>, tolerate abrupt writable close errors, and reduce reconnect flakiness after serial/BLE disconnect (<a href=\"https://github.com/Colorado-Mesh/mesh-client/pull/693\" target=\"_blank\" rel=\"noopener noreferrer\">#693</a>)</li>\n</ul>\n<h3>Other Changes</h3>\n<ul>\n<li><strong>Faster pre-commit</strong> — Staged-related Vitest (<code>test:staged</code>), staged ESLint with cache, and path-gated <code>check:*</code> scanners; PR CI and <code>pnpm run release</code> still run the full suite (<a href=\"https://github.com/Colorado-Mesh/mesh-client/pull/696\" target=\"_blank\" rel=\"noopener noreferrer\">#696</a>)</li>\n<li><strong>Patches / deps</strong> — Track upstream patch PRs in <code>patches/README.md</code> and Ratspeak overlay registry; sync <code>usb</code> MSVC C++17 build flags; routine dependency bumps (<a href=\"https://github.com/Colorado-Mesh/mesh-client/pull/693\" target=\"_blank\" rel=\"noopener noreferrer\">#693</a>, <a href=\"https://github.com/Colorado-Mesh/mesh-client/pull/694\" target=\"_blank\" rel=\"noopener noreferrer\">#694</a>)</li>\n</ul>\n<h3>Breaking Changes</h3>\n<p><em>(None)</em></p>\n<h3>Full Changelog</h3>\n<p><a href=\"https://github.com/Colorado-Mesh/mesh-client/compare/v5.24.0...v5.24.1\" target=\"_blank\" rel=\"noopener noreferrer\"><code>v5.24.0...v5.24.1</code></a></p>\n"
    },
    {
      "version": "v5.24.0",
      "name": "5.24.0",
      "datetime": "2026-07-19T00:29:23Z",
      "url": "https://github.com/Colorado-Mesh/mesh-client/releases/tag/v5.24.0",
      "prerelease": false,
      "notes": "## [v5.24.0] - 2026-07-18\r\n\r\n### Highlights\r\n\r\nReticulum grows into a full comms suite this release: a new **Relay Chat (RRC)** IRC-style multi-hub client, a **Remote** tab for `rnsh` shells and `rncp` file transfer, **watch-folder Nomad hosting** with an upgraded Micron renderer, **identity slots**, propagation-node rename/delete, and much faster **Peers** at large path-table sizes. A broad **protocol-parity** pass adds QR generation/scan, `lxm://` deep links, GPX export, LoRa signal metering, Meshtastic module event history, and per-send **MeshCore flood-scope presets** (now behind a split Send button). Messaging is more resilient (one-click location share, chat outbox drain on reconnect, extended reconnect budgets, humanized send-NAK errors), and cold-start BLE is serialized so an RNode connects before the RF radios. MeshCore MQTT now steers non-Colorado users to LetsMesh by default.\r\n\r\n### What's Changed\r\n\r\n### Features\r\n\r\n- **Reticulum Remote tab (rnsh + rncp)** — New Remote tab (Shell / Transfer / Saved / Settings) with an xterm shell, file send/fetch/listen, saved address book + inbound policy, and Chat DM `rncp` controls; trust-boundary hardening (picker-backed save dirs, size/offer caps, allow/block lists) ([#692](https://github.com/Colorado-Mesh/mesh-client/pull/692), implements [#688](https://github.com/Colorado-Mesh/mesh-client/issues/688), [#689](https://github.com/Colorado-Mesh/mesh-client/issues/689))\r\n- **Reticulum Relay Chat (RRC)** — IRC-style multi-pane client with up to 8 concurrent hub sessions, Favourites/Discovered hub picker, rooms + nicklist, `/`-command router, `@mention` unread badges + tray/toast notifications, and SQLite-persisted room history with retention pruning ([#680](https://github.com/Colorado-Mesh/mesh-client/pull/680), fixes [#648](https://github.com/Colorado-Mesh/mesh-client/issues/648))\r\n- **Watch-folder Nomad hosting + Micron rendering** — Host bounded static Nomad Network sites from a watched folder with auto-restore and filesystem watching; vendored RFnexus Micron parser adds table/anchor/partial support ([#683](https://github.com/Colorado-Mesh/mesh-client/pull/683), closes [#613](https://github.com/Colorado-Mesh/mesh-client/issues/613))\r\n- **Protocol parity tools** — Meshtastic module event history, LoRa signal metering, GPX export, MeshCore MCU temperature parsing, per-send flood-scope overrides, QR generation + camera/file ingest, custom `lxm://` deep links, cross-platform camera permissions, and Reticulum **identity slots** with restart-based switching + contact fingerprint verification ([`9890611e`](https://github.com/Colorado-Mesh/mesh-client/commit/9890611e), fixes [#218](https://github.com/Colorado-Mesh/mesh-client/issues/218), [#477](https://github.com/Colorado-Mesh/mesh-client/issues/477))\r\n- **MeshCore flood-scope presets** — User-managed scope list (seeded from the radio hashtag, cap 20) replacing Colorado/Denver hardcodes; scope now lives behind a chevron split-Send menu instead of an always-visible select ([#692](https://github.com/Colorado-Mesh/mesh-client/pull/692))\r\n- **Messaging resilience** — One-click chat location share (OSM text + optional Meshtastic waypoint) with outbox enqueue on failure, chat outbox drain on RF reconnect, extended BLE/serial reconnect budgets (8 attempts) with transport-aware \"reconnecting N/M\" banner, conservative/aggressive Store & Forward catch-up setting, and a hung-only Reticulum sidecar health watchdog ([#692](https://github.com/Colorado-Mesh/mesh-client/pull/692))\r\n- **Reticulum propagation node management** — Rename/delete remote propagation nodes with confirm dialog and persistence guards ([#679](https://github.com/Colorado-Mesh/mesh-client/pull/679))\r\n- **Scale Reticulum Peers** — Incremental `peers_updated` patches, path-table TTL, forced `?refresh=1` dumps, batched Map updates, and retention parity (hard 100k ceiling / 50k user cap) keep the UI responsive at ~50k peers ([#677](https://github.com/Colorado-Mesh/mesh-client/pull/677\n…",
      "notesHtml": "<h2>[v5.24.0] - 2026-07-18</h2>\n<h3>Highlights</h3>\n<p>Reticulum grows into a full comms suite this release: a new <strong>Relay Chat (RRC)</strong> IRC-style multi-hub client, a <strong>Remote</strong> tab for <code>rnsh</code> shells and <code>rncp</code> file transfer, <strong>watch-folder Nomad hosting</strong> with an upgraded Micron renderer, <strong>identity slots</strong>, propagation-node rename/delete, and much faster <strong>Peers</strong> at large path-table sizes. A broad <strong>protocol-parity</strong> pass adds QR generation/scan, <code>lxm://</code> deep links, GPX export, LoRa signal metering, Meshtastic module event history, and per-send <strong>MeshCore flood-scope presets</strong> (now behind a split Send button). Messaging is more resilient (one-click location share, chat outbox drain on reconnect, extended reconnect budgets, humanized send-NAK errors), and cold-start BLE is serialized so an RNode connects before the RF radios. MeshCore MQTT now steers non-Colorado users to LetsMesh by default.</p>\n<h3>What's Changed</h3>\n<h3>Features</h3>\n<ul>\n<li><strong>Reticulum Remote tab (rnsh + rncp)</strong> — New Remote tab (Shell / Transfer / Saved / Settings) with an xterm shell, file send/fetch/listen, saved address book + inbound policy, and Chat DM <code>rncp</code> controls; trust-boundary hardening (picker-backed save dirs, size/offer caps, allow/block lists) (<a href=\"https://github.com/Colorado-Mesh/mesh-client/pull/692\" target=\"_blank\" rel=\"noopener noreferrer\">#692</a>, implements <a href=\"https://github.com/Colorado-Mesh/mesh-client/issues/688\" target=\"_blank\" rel=\"noopener noreferrer\">#688</a>, <a href=\"https://github.com/Colorado-Mesh/mesh-client/issues/689\" target=\"_blank\" rel=\"noopener noreferrer\">#689</a>)</li>\n<li><strong>Reticulum Relay Chat (RRC)</strong> — IRC-style multi-pane client with up to 8 concurrent hub sessions, Favourites/Discovered hub picker, rooms + nicklist, <code>/</code>-command router, <code>@mention</code> unread badges + tray/toast notifications, and SQLite-persisted room history with retention pruning (<a href=\"https://github.com/Colorado-Mesh/mesh-client/pull/680\" target=\"_blank\" rel=\"noopener noreferrer\">#680</a>, fixes <a href=\"https://github.com/Colorado-Mesh/mesh-client/issues/648\" target=\"_blank\" rel=\"noopener noreferrer\">#648</a>)</li>\n<li><strong>Watch-folder Nomad hosting + Micron rendering</strong> — Host bounded static Nomad Network sites from a watched folder with auto-restore and filesystem watching; vendored RFnexus Micron parser adds table/anchor/partial support (<a href=\"https://github.com/Colorado-Mesh/mesh-client/pull/683\" target=\"_blank\" rel=\"noopener noreferrer\">#683</a>, closes <a href=\"https://github.com/Colorado-Mesh/mesh-client/issues/613\" target=\"_blank\" rel=\"noopener noreferrer\">#613</a>)</li>\n<li><strong>Protocol parity tools</strong> — Meshtastic module event history, LoRa signal metering, GPX export, MeshCore MCU temperature parsing, per-send flood-scope overrides, QR generation + camera/file ingest, custom <code>lxm://</code> deep links, cross-platform camera permissions, and Reticulum <strong>identity slots</strong> with restart-based switching + contact fingerprint verification (<a href=\"https://github.com/Colorado-Mesh/mesh-client/commit/9890611e\" target=\"_blank\" rel=\"noopener noreferrer\"><code>9890611e</code></a>, fixes <a href=\"https://github.com/Colorado-Mesh/mesh-client/issues/218\" target=\"_blank\" rel=\"noopener noreferrer\">#218</a>, <a href=\"https://github.com/Colorado-Mesh/mesh-client/issues/477\" target=\"_blank\" rel=\"noopener noreferrer\">#477</a>)</li>\n<li><strong>MeshCore flood-scope presets</strong> — User-managed scope list (seeded from the radio hashtag, cap 20) replacing Colorado/Denver hardcodes; scope now lives behind a chevron split-Send menu instead of an always-visible select (<a href=\"https://github.com/Colorado-Mesh/mesh-client/pull/692\" target=\"_blank\" rel=\"noopener noreferrer\">#692</a>)</li>\n<li><strong>Messaging resilience</strong> — One-click chat location share (OSM text + optional Meshtastic waypoint) with outbox enqueue on failure, chat outbox drain on RF reconnect, extended BLE/serial reconnect budgets (8 attempts) with transport-aware \"reconnecting N/M\" banner, conservative/aggressive Store &amp; Forward catch-up setting, and a hung-only Reticulum sidecar health watchdog (<a href=\"https://github.com/Colorado-Mesh/mesh-client/pull/692\" target=\"_blank\" rel=\"noopener noreferrer\">#692</a>)</li>\n<li><strong>Reticulum propagation node management</strong> — Rename/delete remote propagation nodes with confirm dialog and persistence guards (<a href=\"https://github.com/Colorado-Mesh/mesh-client/pull/679\" target=\"_blank\" rel=\"noopener noreferrer\">#679</a>)</li>\n<li><strong>Scale Reticulum Peers</strong> — Incremental <code>peers_updated</code> patches, path-table TTL, forced <code>?refresh=1</code> dumps, batched Map updates, and retention parity (hard 100k ceiling / 50k user cap) keep the UI responsive at ~50k peers ([#677](<a href=\"https://github.com/Colorado-Mesh/mesh-client/pull/677\" target=\"_blank\" rel=\"noopener noreferrer\">https://github.com/Colorado-Mesh/mesh-client/pull/677</a>\n…</li>\n</ul>\n"
    },
    {
      "version": "v5.23.0",
      "name": "5.23.0",
      "datetime": "2026-07-14T14:48:08Z",
      "url": "https://github.com/Colorado-Mesh/mesh-client/releases/tag/v5.23.0",
      "prerelease": false,
      "notes": "## [v5.23.0] - 2026-07-14\r\n\r\n### Important: Reticulum contacts cleanup (one-time)\r\n\r\nIf you use Reticulum and see **non-contacts** (peers / announce-only destinations) listed under **Contacts**, that comes from an earlier bug that promoted announces into the contact list. This release stops that pollution going forward, but **existing bad rows are not removed automatically**.\r\n\r\n**One-time fix:** App tab → **Danger Zone** (Reticulum) → **Clear all LXMF contacts**.  \r\nPeers stay on the Peers tab with their names; chat history is kept. Real contacts return when you message someone or use **Save as contact**.\r\n\r\n---\r\n\r\n### Highlights\r\n\r\nReticulum gets much more reliable LXMF DMs (delivery announces, Direct/path-aware sends, saturation hardening), a safer contacts model, faster Peers at large path-table sizes, and interface UX fixes (TCP/UDP/I2P auto-restart, copy LXMF hash, mic for voice clips). Official macOS builds can now be **Developer ID signed and notarized**. Chat hop badges for MeshCore and Meshtastic are fixed, packaging/smoke and long-session stability are hardened, and several flasher / i18n / BT PIN nits land with it.\r\n\r\n### What's Changed\r\n\r\n### Features\r\n\r\n- **Apple code signing and notarization** — Official macOS artifacts can be Developer ID signed and notarized when repo secrets are set; fork/local builds still skip gracefully ([#657](https://github.com/Colorado-Mesh/mesh-client/pull/657))\r\n- **Reticulum interfaces and chat UX** — Auto-restart stack after TCP/UDP/I2P/pipe (and host/port) interface changes; copy full LXMF hash from Network identity; microphone permission path for LXMF voice clips; clearer DM egress badges; DM pills promoted into the main chat row; quieter propagation sync ([#674](https://github.com/Colorado-Mesh/mesh-client/pull/674))\r\n- **Reticulum DM path reachability** — Active DM destination probe / reachability indicator when the stack is live ([#672](https://github.com/Colorado-Mesh/mesh-client/pull/672))\r\n\r\n### Bug Fixes\r\n\r\n- **Reticulum LXMF delivery and inbound receive** — Emit LXMF delivery announces, register inbound destinations, prefer Direct/path-aware signed sends, mark stale queued rows failed ([#672](https://github.com/Colorado-Mesh/mesh-client/pull/672))\r\n- **Reticulum contacts vs announces** — Named announces no longer create contacts; App Danger Zone can clear all LXMF contacts while keeping Peers and chat ([#672](https://github.com/Colorado-Mesh/mesh-client/pull/672))\r\n- **Reticulum under transport saturation** — Path-request backoff, diagnostics for link/timeouts/`share_instance` conflicts, stuck Sending → failed, propagation-node Chat notice ([#669](https://github.com/Colorado-Mesh/mesh-client/pull/669))\r\n- **Reticulum identity / Peers / Nomad** — Restore Reticulum tab on launch; header shows Network display name; faster Peers at large tables and after announces; JSON/msgpack peer name parsing; stack restart race fixes ([#672](https://github.com/Colorado-Mesh/mesh-client/pull/672), [#666](https://github.com/Colorado-Mesh/mesh-client/pull/666), [#667](https://github.com/Colorado-Mesh/mesh-client/pull/667))\r\n- **Reticulum chat polish** — Unread badges clear after reading DMs; hop count restoration; identity/announce defaults ([#674](https://github.com/Colorado-Mesh/mesh-client/pull/674), [#667](https://github.com/Colorado-Mesh/mesh-client/pull/667))\r\n- **Chat hop badges (MeshCore + Meshtastic)** — Companion `pathLen` → hop count; wider raw-log correlation fallback; Meshtastic `viaMqtt` / `hopStart===0` aligned with node/diagnostics semantics ([#670](https://github.com/Colorado-Mesh/mesh-client/pull/670))\r\n- **RNode flasher resilience** — KISS command timeouts, ESP32/nRF52 stall watchdogs, BT pairing timeout, humanized errors ([#664](https://github.com/Colorado-Mesh/mesh-client/pull/664), [#665](https://github.com/Colorado-Mesh/mesh-client/pull/665))\r\n- **Packaging / CI smoke** — ZIP+DMG verification (mount before validate), AppImage extract cwd, no raw `.app` CI uploads, CodeQ\n…",
      "notesHtml": "<h2>[v5.23.0] - 2026-07-14</h2>\n<h3>Important: Reticulum contacts cleanup (one-time)</h3>\n<p>If you use Reticulum and see <strong>non-contacts</strong> (peers / announce-only destinations) listed under <strong>Contacts</strong>, that comes from an earlier bug that promoted announces into the contact list. This release stops that pollution going forward, but <strong>existing bad rows are not removed automatically</strong>.</p>\n<p><strong>One-time fix:</strong> App tab → <strong>Danger Zone</strong> (Reticulum) → <strong>Clear all LXMF contacts</strong>.<br />Peers stay on the Peers tab with their names; chat history is kept. Real contacts return when you message someone or use <strong>Save as contact</strong>.</p>\n<hr />\n<h3>Highlights</h3>\n<p>Reticulum gets much more reliable LXMF DMs (delivery announces, Direct/path-aware sends, saturation hardening), a safer contacts model, faster Peers at large path-table sizes, and interface UX fixes (TCP/UDP/I2P auto-restart, copy LXMF hash, mic for voice clips). Official macOS builds can now be <strong>Developer ID signed and notarized</strong>. Chat hop badges for MeshCore and Meshtastic are fixed, packaging/smoke and long-session stability are hardened, and several flasher / i18n / BT PIN nits land with it.</p>\n<h3>What's Changed</h3>\n<h3>Features</h3>\n<ul>\n<li><strong>Apple code signing and notarization</strong> — Official macOS artifacts can be Developer ID signed and notarized when repo secrets are set; fork/local builds still skip gracefully (<a href=\"https://github.com/Colorado-Mesh/mesh-client/pull/657\" target=\"_blank\" rel=\"noopener noreferrer\">#657</a>)</li>\n<li><strong>Reticulum interfaces and chat UX</strong> — Auto-restart stack after TCP/UDP/I2P/pipe (and host/port) interface changes; copy full LXMF hash from Network identity; microphone permission path for LXMF voice clips; clearer DM egress badges; DM pills promoted into the main chat row; quieter propagation sync (<a href=\"https://github.com/Colorado-Mesh/mesh-client/pull/674\" target=\"_blank\" rel=\"noopener noreferrer\">#674</a>)</li>\n<li><strong>Reticulum DM path reachability</strong> — Active DM destination probe / reachability indicator when the stack is live (<a href=\"https://github.com/Colorado-Mesh/mesh-client/pull/672\" target=\"_blank\" rel=\"noopener noreferrer\">#672</a>)</li>\n</ul>\n<h3>Bug Fixes</h3>\n<ul>\n<li><strong>Reticulum LXMF delivery and inbound receive</strong> — Emit LXMF delivery announces, register inbound destinations, prefer Direct/path-aware signed sends, mark stale queued rows failed (<a href=\"https://github.com/Colorado-Mesh/mesh-client/pull/672\" target=\"_blank\" rel=\"noopener noreferrer\">#672</a>)</li>\n<li><strong>Reticulum contacts vs announces</strong> — Named announces no longer create contacts; App Danger Zone can clear all LXMF contacts while keeping Peers and chat (<a href=\"https://github.com/Colorado-Mesh/mesh-client/pull/672\" target=\"_blank\" rel=\"noopener noreferrer\">#672</a>)</li>\n<li><strong>Reticulum under transport saturation</strong> — Path-request backoff, diagnostics for link/timeouts/<code>share_instance</code> conflicts, stuck Sending → failed, propagation-node Chat notice (<a href=\"https://github.com/Colorado-Mesh/mesh-client/pull/669\" target=\"_blank\" rel=\"noopener noreferrer\">#669</a>)</li>\n<li><strong>Reticulum identity / Peers / Nomad</strong> — Restore Reticulum tab on launch; header shows Network display name; faster Peers at large tables and after announces; JSON/msgpack peer name parsing; stack restart race fixes (<a href=\"https://github.com/Colorado-Mesh/mesh-client/pull/672\" target=\"_blank\" rel=\"noopener noreferrer\">#672</a>, <a href=\"https://github.com/Colorado-Mesh/mesh-client/pull/666\" target=\"_blank\" rel=\"noopener noreferrer\">#666</a>, <a href=\"https://github.com/Colorado-Mesh/mesh-client/pull/667\" target=\"_blank\" rel=\"noopener noreferrer\">#667</a>)</li>\n<li><strong>Reticulum chat polish</strong> — Unread badges clear after reading DMs; hop count restoration; identity/announce defaults (<a href=\"https://github.com/Colorado-Mesh/mesh-client/pull/674\" target=\"_blank\" rel=\"noopener noreferrer\">#674</a>, <a href=\"https://github.com/Colorado-Mesh/mesh-client/pull/667\" target=\"_blank\" rel=\"noopener noreferrer\">#667</a>)</li>\n<li><strong>Chat hop badges (MeshCore + Meshtastic)</strong> — Companion <code>pathLen</code> → hop count; wider raw-log correlation fallback; Meshtastic <code>viaMqtt</code> / <code>hopStart===0</code> aligned with node/diagnostics semantics (<a href=\"https://github.com/Colorado-Mesh/mesh-client/pull/670\" target=\"_blank\" rel=\"noopener noreferrer\">#670</a>)</li>\n<li><strong>RNode flasher resilience</strong> — KISS command timeouts, ESP32/nRF52 stall watchdogs, BT pairing timeout, humanized errors (<a href=\"https://github.com/Colorado-Mesh/mesh-client/pull/664\" target=\"_blank\" rel=\"noopener noreferrer\">#664</a>, <a href=\"https://github.com/Colorado-Mesh/mesh-client/pull/665\" target=\"_blank\" rel=\"noopener noreferrer\">#665</a>)</li>\n<li><strong>Packaging / CI smoke</strong> — ZIP+DMG verification (mount before validate), AppImage extract cwd, no raw <code>.app</code> CI uploads, CodeQ\n…</li>\n</ul>\n"
    },
    {
      "version": "v5.22.0",
      "name": "5.22.0",
      "datetime": "2026-07-11T15:01:25Z",
      "url": "https://github.com/Colorado-Mesh/mesh-client/releases/tag/v5.22.0",
      "prerelease": false,
      "notes": "## [v5.22.0] - 2026-07-11\r\n\r\n### Highlights\r\n\r\nThis release adds **Reticulum RMAP v4 discovery** (publish, per-interface controls, and a local discovery map tab), **unified Reticulum identity import**, and a much more scannable **Sniffer** tab across all protocols. It also fixes Meshtastic MQTT messages landing on the wrong channel tab, hardens **triple-protocol BLE coexistence** when Reticulum uses a Noble RNode alongside Meshtastic/MeshCore, and migrates the Colorado Mesh MQTT preset to **port 443**.\r\n\r\n### What's Changed\r\n\r\n### Features\r\n\r\n- **Reticulum RMAP v4 discovery** — Publish enabled interfaces to RMAP v4 using App GPS coordinates; per-interface discoverable toggles for RNode, KISS, BLE peer, I2P, UDP, and pipe; Connection tab status strip and sync badges; default hub sync with skip/repair/add; new **Map** tab with local discovery map (Leaflet), filters, path-table reachability, and link to [rmap.world](https://rmap.world/) ([#649](https://github.com/Colorado-Mesh/mesh-client/pull/649))\r\n- **Reticulum identity unification and import** — Single unified identity apply path in the sidecar; backup JSON and private key import (hex/base64/file) on the Network tab with replace confirmation ([#651](https://github.com/Colorado-Mesh/mesh-client/pull/651))\r\n- **Sniffer tab scanability** — MeshCore on-air hop chains and path display; Meshtastic collapsed hops and transport/type badges; sortable columns, quick-filter chips, relative timestamps, and hover tooltips across all protocols ([#643](https://github.com/Colorado-Mesh/mesh-client/pull/643))\r\n\r\n### Bug Fixes\r\n\r\n- **Meshtastic MQTT channel routing** — Prefer MQTT topic channel name over sender-local `MeshPacket.channel` slot for inbound text; add `@index` hint in Connection panel for MQTT-only setups ([#644](https://github.com/Colorado-Mesh/mesh-client/pull/644))\r\n- **Triple-protocol BLE coexistence** — Suspend Noble for Reticulum RNode pairing on macOS/Windows; paired yield lifecycle so the scan mutex releases on connect, grace expiry, or sidecar stop; reconnect hardening and quieter logs when Meshtastic/MeshCore resume after yield ([#645](https://github.com/Colorado-Mesh/mesh-client/pull/645), [#653](https://github.com/Colorado-Mesh/mesh-client/pull/653), [#655](https://github.com/Colorado-Mesh/mesh-client/pull/655))\r\n- **Colorado Mesh MQTT preset** — Align MeshCore broker preset to TLS WebSocket on port **443**; migrate saved settings off legacy port 1883 ([#647](https://github.com/Colorado-Mesh/mesh-client/pull/647), [#651](https://github.com/Colorado-Mesh/mesh-client/pull/651))\r\n- **Reticulum discovery map resilience** — Cap discovery rows (2,000) with 7-day TTL eviction; preserve last-good data on fetch failure; clear stores on disconnect; partial-failure toasts for RMAP apply/disable ([#650](https://github.com/Colorado-Mesh/mesh-client/pull/650))\r\n- **Meshtastic TCP connect** — 20s timeout aligned with other transports; disconnect orphaned sockets on failed connect ([#644](https://github.com/Colorado-Mesh/mesh-client/pull/644))\r\n- **Channel PSK validation** — Reject keys shorter than 16 bytes; accept 1-byte default PSK and bare decrypt-only lengths consistent with MQTT manager ([#646](https://github.com/Colorado-Mesh/mesh-client/pull/646), [#651](https://github.com/Colorado-Mesh/mesh-client/pull/651))\r\n- **Reticulum diagnostics** — Omit expected SharedInstanceServer runtime note from actionable faults ([#652](https://github.com/Colorado-Mesh/mesh-client/pull/652))\r\n- **I2P peer validation** — Accept official 60-char testnet `.b32.i2p` addresses ([#649](https://github.com/Colorado-Mesh/mesh-client/pull/649))\r\n- **MeshCore waiting-messages poll** — Gate idle 5-minute safety poll; treat silent sync timeouts as empty queue ([#655](https://github.com/Colorado-Mesh/mesh-client/pull/655))\r\n- **Connection banner accessibility** — Status region labels, decorative reconnect pulse layer, improved contrast ([#655](https://github.com/Colorado-Mesh/mesh-client/pull/655))\r\n\r\n### Othe\n…",
      "notesHtml": "<h2>[v5.22.0] - 2026-07-11</h2>\n<h3>Highlights</h3>\n<p>This release adds <strong>Reticulum RMAP v4 discovery</strong> (publish, per-interface controls, and a local discovery map tab), <strong>unified Reticulum identity import</strong>, and a much more scannable <strong>Sniffer</strong> tab across all protocols. It also fixes Meshtastic MQTT messages landing on the wrong channel tab, hardens <strong>triple-protocol BLE coexistence</strong> when Reticulum uses a Noble RNode alongside Meshtastic/MeshCore, and migrates the Colorado Mesh MQTT preset to <strong>port 443</strong>.</p>\n<h3>What's Changed</h3>\n<h3>Features</h3>\n<ul>\n<li><strong>Reticulum RMAP v4 discovery</strong> — Publish enabled interfaces to RMAP v4 using App GPS coordinates; per-interface discoverable toggles for RNode, KISS, BLE peer, I2P, UDP, and pipe; Connection tab status strip and sync badges; default hub sync with skip/repair/add; new <strong>Map</strong> tab with local discovery map (Leaflet), filters, path-table reachability, and link to <a href=\"https://rmap.world/\" target=\"_blank\" rel=\"noopener noreferrer\">rmap.world</a> (<a href=\"https://github.com/Colorado-Mesh/mesh-client/pull/649\" target=\"_blank\" rel=\"noopener noreferrer\">#649</a>)</li>\n<li><strong>Reticulum identity unification and import</strong> — Single unified identity apply path in the sidecar; backup JSON and private key import (hex/base64/file) on the Network tab with replace confirmation (<a href=\"https://github.com/Colorado-Mesh/mesh-client/pull/651\" target=\"_blank\" rel=\"noopener noreferrer\">#651</a>)</li>\n<li><strong>Sniffer tab scanability</strong> — MeshCore on-air hop chains and path display; Meshtastic collapsed hops and transport/type badges; sortable columns, quick-filter chips, relative timestamps, and hover tooltips across all protocols (<a href=\"https://github.com/Colorado-Mesh/mesh-client/pull/643\" target=\"_blank\" rel=\"noopener noreferrer\">#643</a>)</li>\n</ul>\n<h3>Bug Fixes</h3>\n<ul>\n<li><strong>Meshtastic MQTT channel routing</strong> — Prefer MQTT topic channel name over sender-local <code>MeshPacket.channel</code> slot for inbound text; add <code>@index</code> hint in Connection panel for MQTT-only setups (<a href=\"https://github.com/Colorado-Mesh/mesh-client/pull/644\" target=\"_blank\" rel=\"noopener noreferrer\">#644</a>)</li>\n<li><strong>Triple-protocol BLE coexistence</strong> — Suspend Noble for Reticulum RNode pairing on macOS/Windows; paired yield lifecycle so the scan mutex releases on connect, grace expiry, or sidecar stop; reconnect hardening and quieter logs when Meshtastic/MeshCore resume after yield (<a href=\"https://github.com/Colorado-Mesh/mesh-client/pull/645\" target=\"_blank\" rel=\"noopener noreferrer\">#645</a>, <a href=\"https://github.com/Colorado-Mesh/mesh-client/pull/653\" target=\"_blank\" rel=\"noopener noreferrer\">#653</a>, <a href=\"https://github.com/Colorado-Mesh/mesh-client/pull/655\" target=\"_blank\" rel=\"noopener noreferrer\">#655</a>)</li>\n<li><strong>Colorado Mesh MQTT preset</strong> — Align MeshCore broker preset to TLS WebSocket on port <strong>443</strong>; migrate saved settings off legacy port 1883 (<a href=\"https://github.com/Colorado-Mesh/mesh-client/pull/647\" target=\"_blank\" rel=\"noopener noreferrer\">#647</a>, <a href=\"https://github.com/Colorado-Mesh/mesh-client/pull/651\" target=\"_blank\" rel=\"noopener noreferrer\">#651</a>)</li>\n<li><strong>Reticulum discovery map resilience</strong> — Cap discovery rows (2,000) with 7-day TTL eviction; preserve last-good data on fetch failure; clear stores on disconnect; partial-failure toasts for RMAP apply/disable (<a href=\"https://github.com/Colorado-Mesh/mesh-client/pull/650\" target=\"_blank\" rel=\"noopener noreferrer\">#650</a>)</li>\n<li><strong>Meshtastic TCP connect</strong> — 20s timeout aligned with other transports; disconnect orphaned sockets on failed connect (<a href=\"https://github.com/Colorado-Mesh/mesh-client/pull/644\" target=\"_blank\" rel=\"noopener noreferrer\">#644</a>)</li>\n<li><strong>Channel PSK validation</strong> — Reject keys shorter than 16 bytes; accept 1-byte default PSK and bare decrypt-only lengths consistent with MQTT manager (<a href=\"https://github.com/Colorado-Mesh/mesh-client/pull/646\" target=\"_blank\" rel=\"noopener noreferrer\">#646</a>, <a href=\"https://github.com/Colorado-Mesh/mesh-client/pull/651\" target=\"_blank\" rel=\"noopener noreferrer\">#651</a>)</li>\n<li><strong>Reticulum diagnostics</strong> — Omit expected SharedInstanceServer runtime note from actionable faults (<a href=\"https://github.com/Colorado-Mesh/mesh-client/pull/652\" target=\"_blank\" rel=\"noopener noreferrer\">#652</a>)</li>\n<li><strong>I2P peer validation</strong> — Accept official 60-char testnet <code>.b32.i2p</code> addresses (<a href=\"https://github.com/Colorado-Mesh/mesh-client/pull/649\" target=\"_blank\" rel=\"noopener noreferrer\">#649</a>)</li>\n<li><strong>MeshCore waiting-messages poll</strong> — Gate idle 5-minute safety poll; treat silent sync timeouts as empty queue (<a href=\"https://github.com/Colorado-Mesh/mesh-client/pull/655\" target=\"_blank\" rel=\"noopener noreferrer\">#655</a>)</li>\n<li><strong>Connection banner accessibility</strong> — Status region labels, decorative reconnect pulse layer, improved contrast (<a href=\"https://github.com/Colorado-Mesh/mesh-client/pull/655\" target=\"_blank\" rel=\"noopener noreferrer\">#655</a>)</li>\n</ul>\n<h3>Othe</h3>\n<p>…</p>\n"
    },
    {
      "version": "v5.21.2",
      "name": "5.21.2",
      "datetime": "2026-07-09T20:06:10Z",
      "url": "https://github.com/Colorado-Mesh/mesh-client/releases/tag/v5.21.2",
      "prerelease": false,
      "notes": "## [v5.21.2] - 2026-07-09\r\n\r\n### Highlights\r\n\r\n**Meshtastic Wi-Fi (TCP, fast)** adds a new connection mode on port 4403 — the same native binary stream as USB serial — so a large NodeDB can configure in about a second instead of 40–60+ seconds over HTTP. This patch also **fixes Meshtastic HTTP/Wi-Fi connect** (host validation and concurrent write locking), **continues MQTT channel-slot attribution fixes** (prefer `MeshPacket.channel` over topic mapping), and **scopes MeshCore message-sync spinners** to the MeshCore tab so other protocol tabs no longer look busy during background drain.\r\n\r\n### Features\r\n\r\n- Meshtastic **Wi-Fi (TCP, fast)** connection option on port 4403 ([#640](https://github.com/Colorado-Mesh/mesh-client/pull/640))\r\n  - New **Wi-Fi (TCP, fast)** transport alongside Bluetooth, USB Serial, and Wi-Fi (HTTP)\r\n  - Main-process `meshtastic:tcp-*` IPC bridge and renderer `TransportTcpIpc` using Meshtastic core framing\r\n  - Serialized outbound writes and heartbeat gating (same SDK concurrency fix as HTTP)\r\n  - Reliable disconnect/reconnect: `safeDisconnect` now tears down HTTP/TCP sockets when the SDK throws before calling `transport.disconnect()`\r\n\r\n### Bug Fixes\r\n\r\n- Validate `host:port` authority in `http:preflight` / `http:connect` — strip port before hostname check so Meshtastic HTTP connect works again ([#638](https://github.com/Colorado-Mesh/mesh-client/pull/638))\r\n- Serialize concurrent Meshtastic transport writes for HTTP connect — fixes `\"WritableStream is locked\"` drops that left chat sends unacknowledged ([#639](https://github.com/Colorado-Mesh/mesh-client/pull/639))\r\n- Attribute inbound Meshtastic MQTT text to **`MeshPacket.channel`** (0–7) instead of topic-name mapping; fixes public traffic landing in slot 0 when the topic map is stale ([#641](https://github.com/Colorado-Mesh/mesh-client/pull/641))\r\n- Route JSON MQTT text through the same channel-index resolver as protobuf ingest\r\n- Scope MeshCore message-sync spinner to the **MeshCore tab** only; queued backlog pill stays cross-tab ([#637](https://github.com/Colorado-Mesh/mesh-client/pull/637))\r\n- Harden IPC and Flatpak sync ([#641](https://github.com/Colorado-Mesh/mesh-client/pull/641))\r\n  - 15s timeout on Linux `bluetooth-start-scan` so hung `bluetoothctl scan on` cannot block pairing forever\r\n  - Async `meshcore:openJsonFile` read (no sync I/O on the main thread)\r\n  - CodeQL hardening in `sync-flatpak-electron` (semver assert, checksum validation, sanitized manifest writes)\r\n- Auto-merge duplicate GitHub draft releases in CI — merge split assets, delete extra drafts, and gate smoke tests after consolidation ([#628](https://github.com/Colorado-Mesh/mesh-client/pull/628) follow-up)\r\n\r\n### Other Changes\r\n\r\n- Extend debug snapshot with `channelPills`, `channelConfigsSummary`, and `mqttChannelKeyEntryCount` for support-bundle triage ([#641](https://github.com/Colorado-Mesh/mesh-client/pull/641))\r\n- Document Meshtastic MQTT channel ingest and triage in AGENTS.md and troubleshooting.md\r\n- Use `Set` for renderer lib UI fallback lookup in Vitest config (O(1) membership vs linear `.includes()`) ([#642](https://github.com/Colorado-Mesh/mesh-client/pull/642))\r\n- Bump deps ([#641](https://github.com/Colorado-Mesh/mesh-client/pull/641))\r\n\r\n### Breaking Changes\r\n\r\n*(None)*\r\n\r\n### Full Changelog\r\n\r\n[`v5.21.1...v5.21.2`](https://github.com/Colorado-Mesh/mesh-client/compare/v5.21.1...v5.21.2)",
      "notesHtml": "<h2>[v5.21.2] - 2026-07-09</h2>\n<h3>Highlights</h3>\n<p><strong>Meshtastic Wi-Fi (TCP, fast)</strong> adds a new connection mode on port 4403 — the same native binary stream as USB serial — so a large NodeDB can configure in about a second instead of 40–60+ seconds over HTTP. This patch also <strong>fixes Meshtastic HTTP/Wi-Fi connect</strong> (host validation and concurrent write locking), <strong>continues MQTT channel-slot attribution fixes</strong> (prefer <code>MeshPacket.channel</code> over topic mapping), and <strong>scopes MeshCore message-sync spinners</strong> to the MeshCore tab so other protocol tabs no longer look busy during background drain.</p>\n<h3>Features</h3>\n<ul>\n<li>Meshtastic <strong>Wi-Fi (TCP, fast)</strong> connection option on port 4403 (<a href=\"https://github.com/Colorado-Mesh/mesh-client/pull/640\" target=\"_blank\" rel=\"noopener noreferrer\">#640</a>)<ul>\n<li>New <strong>Wi-Fi (TCP, fast)</strong> transport alongside Bluetooth, USB Serial, and Wi-Fi (HTTP)</li>\n<li>Main-process <code>meshtastic:tcp-*</code> IPC bridge and renderer <code>TransportTcpIpc</code> using Meshtastic core framing</li>\n<li>Serialized outbound writes and heartbeat gating (same SDK concurrency fix as HTTP)</li>\n<li>Reliable disconnect/reconnect: <code>safeDisconnect</code> now tears down HTTP/TCP sockets when the SDK throws before calling <code>transport.disconnect()</code></li>\n</ul>\n</li>\n</ul>\n<h3>Bug Fixes</h3>\n<ul>\n<li>Validate <code>host:port</code> authority in <code>http:preflight</code> / <code>http:connect</code> — strip port before hostname check so Meshtastic HTTP connect works again (<a href=\"https://github.com/Colorado-Mesh/mesh-client/pull/638\" target=\"_blank\" rel=\"noopener noreferrer\">#638</a>)</li>\n<li>Serialize concurrent Meshtastic transport writes for HTTP connect — fixes <code>\"WritableStream is locked\"</code> drops that left chat sends unacknowledged (<a href=\"https://github.com/Colorado-Mesh/mesh-client/pull/639\" target=\"_blank\" rel=\"noopener noreferrer\">#639</a>)</li>\n<li>Attribute inbound Meshtastic MQTT text to <strong><code>MeshPacket.channel</code></strong> (0–7) instead of topic-name mapping; fixes public traffic landing in slot 0 when the topic map is stale (<a href=\"https://github.com/Colorado-Mesh/mesh-client/pull/641\" target=\"_blank\" rel=\"noopener noreferrer\">#641</a>)</li>\n<li>Route JSON MQTT text through the same channel-index resolver as protobuf ingest</li>\n<li>Scope MeshCore message-sync spinner to the <strong>MeshCore tab</strong> only; queued backlog pill stays cross-tab (<a href=\"https://github.com/Colorado-Mesh/mesh-client/pull/637\" target=\"_blank\" rel=\"noopener noreferrer\">#637</a>)</li>\n<li>Harden IPC and Flatpak sync (<a href=\"https://github.com/Colorado-Mesh/mesh-client/pull/641\" target=\"_blank\" rel=\"noopener noreferrer\">#641</a>)<ul>\n<li>15s timeout on Linux <code>bluetooth-start-scan</code> so hung <code>bluetoothctl scan on</code> cannot block pairing forever</li>\n<li>Async <code>meshcore:openJsonFile</code> read (no sync I/O on the main thread)</li>\n<li>CodeQL hardening in <code>sync-flatpak-electron</code> (semver assert, checksum validation, sanitized manifest writes)</li>\n</ul>\n</li>\n<li>Auto-merge duplicate GitHub draft releases in CI — merge split assets, delete extra drafts, and gate smoke tests after consolidation (<a href=\"https://github.com/Colorado-Mesh/mesh-client/pull/628\" target=\"_blank\" rel=\"noopener noreferrer\">#628</a> follow-up)</li>\n</ul>\n<h3>Other Changes</h3>\n<ul>\n<li>Extend debug snapshot with <code>channelPills</code>, <code>channelConfigsSummary</code>, and <code>mqttChannelKeyEntryCount</code> for support-bundle triage (<a href=\"https://github.com/Colorado-Mesh/mesh-client/pull/641\" target=\"_blank\" rel=\"noopener noreferrer\">#641</a>)</li>\n<li>Document Meshtastic MQTT channel ingest and triage in AGENTS.md and troubleshooting.md</li>\n<li>Use <code>Set</code> for renderer lib UI fallback lookup in Vitest config (O(1) membership vs linear <code>.includes()</code>) (<a href=\"https://github.com/Colorado-Mesh/mesh-client/pull/642\" target=\"_blank\" rel=\"noopener noreferrer\">#642</a>)</li>\n<li>Bump deps (<a href=\"https://github.com/Colorado-Mesh/mesh-client/pull/641\" target=\"_blank\" rel=\"noopener noreferrer\">#641</a>)</li>\n</ul>\n<h3>Breaking Changes</h3>\n<p><em>(None)</em></p>\n<h3>Full Changelog</h3>\n<p><a href=\"https://github.com/Colorado-Mesh/mesh-client/compare/v5.21.1...v5.21.2\" target=\"_blank\" rel=\"noopener noreferrer\"><code>v5.21.1...v5.21.2</code></a></p>\n"
    },
    {
      "version": "v5.21.1",
      "name": "5.21.1",
      "datetime": "2026-07-08T23:45:09Z",
      "url": "https://github.com/Colorado-Mesh/mesh-client/releases/tag/v5.21.1",
      "prerelease": false,
      "notes": "## [v5.21.1] - 2026-07-08\r\n\r\n### Highlights\r\n\r\n**Reticulum** is now a full third protocol tab alongside Meshtastic and MeshCore — Rust sidecar, complete UI, RNode flasher/BLE/Wi‑Fi, and triple-protocol BLE coexistence ([#593](https://github.com/Colorado-Mesh/mesh-client/issues/593) / [#596](https://github.com/Colorado-Mesh/mesh-client/pull/596)). **MeshCore** gains per-repeater saved passwords, more reliable repeater admin RPCs, and multi-hop trace/ping fixes. **Nomad Network** adds a Micron browser and session-persistent browse state.\r\n\r\nThis release also fixes **Meshtastic MQTT LongFast** channel slot attribution (including bare PSK on channel 0), hardens **release CI** against duplicate draft uploads and tag-move smoke failures, syncs **Flatpak** Electron archives during release builds, and improves link-preview timeout UX.\r\n\r\n### Features\r\n\r\n- Reticulum third protocol — Ratspeak sidecar, MeshChat UX parity, RNode flasher/BLE/Wi‑Fi, triple-protocol BLE, peer graph overhaul & repo-wide i18n (Fixes #593) ([#596](https://github.com/Colorado-Mesh/mesh-client/pull/596))\r\n- Reticulum RNode selection, IPv6 connect, and quality audit hardening ([#610](https://github.com/Colorado-Mesh/mesh-client/pull/610))\r\n- Nomad Micron browser, docs refresh, and large repeater book hardening ([#611](https://github.com/Colorado-Mesh/mesh-client/pull/611))\r\n- Reticulum export diagnostics, default TCP hubs, and MeshCore header waiting-message status ([#620](https://github.com/Colorado-Mesh/mesh-client/pull/620))\r\n- Reticulum hub presets, security hardening, and packaging fixes ([#621](https://github.com/Colorado-Mesh/mesh-client/pull/621))\r\n- Local act CI (container + native) and Flatpak smoke-test fix ([#604](https://github.com/Colorado-Mesh/mesh-client/pull/604))\r\n\r\n### Bug Fixes\r\n\r\n- Sync Flatpak Electron archives during release\r\n- Align electronAPI stubs with typed IPC surface ([#636](https://github.com/Colorado-Mesh/mesh-client/pull/636))\r\n- MQTT LongFast slot attribution and regional topic scope ([#635](https://github.com/Colorado-Mesh/mesh-client/pull/635))\r\n- Populate MQTT channel 0 from bare PSK alongside named secondaries ([#634](https://github.com/Colorado-Mesh/mesh-client/pull/634))\r\n- Attribute MQTT LongFast messages to configured channel slot ([#633](https://github.com/Colorado-Mesh/mesh-client/pull/633))\r\n- Link preview timeout dialog and release workflow permissions ([#631](https://github.com/Colorado-Mesh/mesh-client/pull/631))\r\n- Harden release workflow against duplicate drafts and retag races ([#628](https://github.com/Colorado-Mesh/mesh-client/pull/628))\r\n- Pin packaging-smoke checkout to `github.sha`\r\n- Filter release workflow matrix via `workflow_dispatch` platforms\r\n- Dedupe GitHub draft releases and consolidate split assets\r\n- Gate release publish on single draft GitHub release ([#627](https://github.com/Colorado-Mesh/mesh-client/pull/627))\r\n- Fail tests on parseStoredJson `[object Object]` release noise ([#626](https://github.com/Colorado-Mesh/mesh-client/pull/626))\r\n- MeshCore multi-hop trace priming, visible ping errors, and CI/hardening follow-ups ([#625](https://github.com/Colorado-Mesh/mesh-client/pull/625))\r\n- Harden arm64 apt CI setup script for re-runs and release upgrades ([#624](https://github.com/Colorado-Mesh/mesh-client/pull/624))\r\n- Stop MeshCore auto-reconnect after manual disconnect ([#623](https://github.com/Colorado-Mesh/mesh-client/pull/623))\r\n- Audit follow-ups for UX, hardening, i18n, and Reticulum I2P ([#622](https://github.com/Colorado-Mesh/mesh-client/pull/622))\r\n- Reticulum sidecar bundling, support exports, MeshCore drain, and peers/contacts split ([#616](https://github.com/Colorado-Mesh/mesh-client/pull/616))\r\n- Configure apt for Linux arm64 cross-build on Ubuntu 24.04 CI ([#617](https://github.com/Colorado-Mesh/mesh-client/pull/617))\r\n- Linux AppImage smoke test extract directory ENOENT ([#618](https://github.com/Colorado-Mesh/mesh-client/pull/618))\r\n- Extract arm64 AppImages on x64 CI with unsqu\n…",
      "notesHtml": "<h2>[v5.21.1] - 2026-07-08</h2>\n<h3>Highlights</h3>\n<p><strong>Reticulum</strong> is now a full third protocol tab alongside Meshtastic and MeshCore — Rust sidecar, complete UI, RNode flasher/BLE/Wi‑Fi, and triple-protocol BLE coexistence (<a href=\"https://github.com/Colorado-Mesh/mesh-client/issues/593\" target=\"_blank\" rel=\"noopener noreferrer\">#593</a> / <a href=\"https://github.com/Colorado-Mesh/mesh-client/pull/596\" target=\"_blank\" rel=\"noopener noreferrer\">#596</a>). <strong>MeshCore</strong> gains per-repeater saved passwords, more reliable repeater admin RPCs, and multi-hop trace/ping fixes. <strong>Nomad Network</strong> adds a Micron browser and session-persistent browse state.</p>\n<p>This release also fixes <strong>Meshtastic MQTT LongFast</strong> channel slot attribution (including bare PSK on channel 0), hardens <strong>release CI</strong> against duplicate draft uploads and tag-move smoke failures, syncs <strong>Flatpak</strong> Electron archives during release builds, and improves link-preview timeout UX.</p>\n<h3>Features</h3>\n<ul>\n<li>Reticulum third protocol — Ratspeak sidecar, MeshChat UX parity, RNode flasher/BLE/Wi‑Fi, triple-protocol BLE, peer graph overhaul &amp; repo-wide i18n (Fixes #593) (<a href=\"https://github.com/Colorado-Mesh/mesh-client/pull/596\" target=\"_blank\" rel=\"noopener noreferrer\">#596</a>)</li>\n<li>Reticulum RNode selection, IPv6 connect, and quality audit hardening (<a href=\"https://github.com/Colorado-Mesh/mesh-client/pull/610\" target=\"_blank\" rel=\"noopener noreferrer\">#610</a>)</li>\n<li>Nomad Micron browser, docs refresh, and large repeater book hardening (<a href=\"https://github.com/Colorado-Mesh/mesh-client/pull/611\" target=\"_blank\" rel=\"noopener noreferrer\">#611</a>)</li>\n<li>Reticulum export diagnostics, default TCP hubs, and MeshCore header waiting-message status (<a href=\"https://github.com/Colorado-Mesh/mesh-client/pull/620\" target=\"_blank\" rel=\"noopener noreferrer\">#620</a>)</li>\n<li>Reticulum hub presets, security hardening, and packaging fixes (<a href=\"https://github.com/Colorado-Mesh/mesh-client/pull/621\" target=\"_blank\" rel=\"noopener noreferrer\">#621</a>)</li>\n<li>Local act CI (container + native) and Flatpak smoke-test fix (<a href=\"https://github.com/Colorado-Mesh/mesh-client/pull/604\" target=\"_blank\" rel=\"noopener noreferrer\">#604</a>)</li>\n</ul>\n<h3>Bug Fixes</h3>\n<ul>\n<li>Sync Flatpak Electron archives during release</li>\n<li>Align electronAPI stubs with typed IPC surface (<a href=\"https://github.com/Colorado-Mesh/mesh-client/pull/636\" target=\"_blank\" rel=\"noopener noreferrer\">#636</a>)</li>\n<li>MQTT LongFast slot attribution and regional topic scope (<a href=\"https://github.com/Colorado-Mesh/mesh-client/pull/635\" target=\"_blank\" rel=\"noopener noreferrer\">#635</a>)</li>\n<li>Populate MQTT channel 0 from bare PSK alongside named secondaries (<a href=\"https://github.com/Colorado-Mesh/mesh-client/pull/634\" target=\"_blank\" rel=\"noopener noreferrer\">#634</a>)</li>\n<li>Attribute MQTT LongFast messages to configured channel slot (<a href=\"https://github.com/Colorado-Mesh/mesh-client/pull/633\" target=\"_blank\" rel=\"noopener noreferrer\">#633</a>)</li>\n<li>Link preview timeout dialog and release workflow permissions (<a href=\"https://github.com/Colorado-Mesh/mesh-client/pull/631\" target=\"_blank\" rel=\"noopener noreferrer\">#631</a>)</li>\n<li>Harden release workflow against duplicate drafts and retag races (<a href=\"https://github.com/Colorado-Mesh/mesh-client/pull/628\" target=\"_blank\" rel=\"noopener noreferrer\">#628</a>)</li>\n<li>Pin packaging-smoke checkout to <code>github.sha</code></li>\n<li>Filter release workflow matrix via <code>workflow_dispatch</code> platforms</li>\n<li>Dedupe GitHub draft releases and consolidate split assets</li>\n<li>Gate release publish on single draft GitHub release (<a href=\"https://github.com/Colorado-Mesh/mesh-client/pull/627\" target=\"_blank\" rel=\"noopener noreferrer\">#627</a>)</li>\n<li>Fail tests on parseStoredJson <code>[object Object]</code> release noise (<a href=\"https://github.com/Colorado-Mesh/mesh-client/pull/626\" target=\"_blank\" rel=\"noopener noreferrer\">#626</a>)</li>\n<li>MeshCore multi-hop trace priming, visible ping errors, and CI/hardening follow-ups (<a href=\"https://github.com/Colorado-Mesh/mesh-client/pull/625\" target=\"_blank\" rel=\"noopener noreferrer\">#625</a>)</li>\n<li>Harden arm64 apt CI setup script for re-runs and release upgrades (<a href=\"https://github.com/Colorado-Mesh/mesh-client/pull/624\" target=\"_blank\" rel=\"noopener noreferrer\">#624</a>)</li>\n<li>Stop MeshCore auto-reconnect after manual disconnect (<a href=\"https://github.com/Colorado-Mesh/mesh-client/pull/623\" target=\"_blank\" rel=\"noopener noreferrer\">#623</a>)</li>\n<li>Audit follow-ups for UX, hardening, i18n, and Reticulum I2P (<a href=\"https://github.com/Colorado-Mesh/mesh-client/pull/622\" target=\"_blank\" rel=\"noopener noreferrer\">#622</a>)</li>\n<li>Reticulum sidecar bundling, support exports, MeshCore drain, and peers/contacts split (<a href=\"https://github.com/Colorado-Mesh/mesh-client/pull/616\" target=\"_blank\" rel=\"noopener noreferrer\">#616</a>)</li>\n<li>Configure apt for Linux arm64 cross-build on Ubuntu 24.04 CI (<a href=\"https://github.com/Colorado-Mesh/mesh-client/pull/617\" target=\"_blank\" rel=\"noopener noreferrer\">#617</a>)</li>\n<li>Linux AppImage smoke test extract directory ENOENT (<a href=\"https://github.com/Colorado-Mesh/mesh-client/pull/618\" target=\"_blank\" rel=\"noopener noreferrer\">#618</a>)</li>\n<li>Extract arm64 AppImages on x64 CI with unsqu\n…</li>\n</ul>\n"
    },
    {
      "version": "v5.21.0",
      "name": "5.21.0",
      "datetime": "2026-07-08T00:47:41Z",
      "url": "https://github.com/Colorado-Mesh/mesh-client/releases/tag/v5.21.0",
      "prerelease": true,
      "notes": "## [v5.21.0] - 2026-07-07\r\n\r\nNote: GitHub had lots of problems publishing this release. If you find a broken build, please file an issue.\r\n\r\n### Highlights\r\n\r\nThis release adds **Reticulum** as mesh-client's third protocol (Ratspeak sidecar, RNode flasher/BLE/Wi-Fi, triple-protocol BLE coexistence, and MeshChat UX parity). **MeshCore repeater admin** gains per-repeater saved passwords and more reliable RPCs. **Nomad Network** adds a Micron browser and large-scale mesh hardening. Packaging and CI improvements cover Flatpak, Linux arm64 cross-builds, local `act` workflows, and safer draft-release publishing.\r\n\r\n### Features\r\n\r\n- Reticulum third protocol — Ratspeak sidecar, MeshChat UX parity, RNode flasher/BLE/Wi-Fi, triple-protocol BLE, peer graph overhaul & repo-wide i18n (Fixes #593) (#596)\r\n- Nomad Micron browser, docs refresh, and large repeater book hardening (#611)\r\n- Reticulum RNode selection, IPv6 connect, and quality audit hardening (#610)\r\n- Reticulum export diagnostics, default TCP hubs, and MeshCore header waiting-message status (#620)\r\n- Reticulum hub presets, security hardening, and packaging fixes (#621)\r\n- Local act CI (container + native) and Flatpak smoke-test fix (#604)\r\n\r\nAlso in this release: MeshCore repeater admin RPC reliability and per-repeater passwords (#614); Nomad Network UX, 10k mesh scale, CI perf, and stack hardening (#612).\r\n\r\n### Bug Fixes\r\n\r\n- Gate release publish on single draft GitHub release (#627)\r\n- Fail tests on parseStoredJson `[object Object]` release noise (#626)\r\n- MeshCore multi-hop trace priming, visible ping errors, and CI/hardening follow-ups (#625)\r\n- Harden arm64 apt CI setup script for re-runs and release upgrades (#624)\r\n- Stop MeshCore auto-reconnect after manual disconnect (#623)\r\n- Audit follow-ups for UX, hardening, i18n, and Reticulum I2P (#622)\r\n- Extract arm64 AppImages on x64 CI with unsquashfs (#619)\r\n- Linux AppImage smoke test extract directory ENOENT (#618)\r\n- Configure apt for Linux arm64 cross-build on Ubuntu 24.04 CI (#617)\r\n- Reticulum sidecar bundling, support exports, MeshCore drain, and peers/contacts split (#616)\r\n- Protocol-scoped diagnostics, language selector UX, and docs refresh (#609)\r\n- Harden long MeshCore sessions against RPC races and memory growth (#608)\r\n- Auto-apply rsReticulum packet-tap overlay for sidecar builds (#607)\r\n- Stop Reticulum utun beacon log spam and surface Meshtastic PKI send errors (#605)\r\n- Flatpak sidecar CI and actionlint installer (#603)\r\n- Use dnf for Reticulum sidecar deps in Flatpak CI (#602)\r\n- Flatpak Wayland launch, MeshCore queue badge, Reticulum DMs by address, and CodeQL findings (#601)\r\n- Compare MeshCore firmware updates by semver, not build date (#595)\r\n\r\n### Other Changes\r\n\r\n- Generalize App orchestration for N-protocol prep (#597)\r\n- N-protocol renderer prep + MeshCore multibyte path hash (#594)\r\n- Consolidate timeConstants shared import for CodeQL (#615)\r\n- Sync reticulum-sidecar Cargo.lock for rns-interface deps (#606)\r\n\r\n### Breaking Changes\r\n\r\n*(None)*\r\n\r\n### Full Changelog\r\n\r\n[`v5.20.4...v5.21.0`](https://github.com/Colorado-Mesh/mesh-client/compare/v5.20.4...v5.21.0)",
      "notesHtml": "<h2>[v5.21.0] - 2026-07-07</h2>\n<p>Note: GitHub had lots of problems publishing this release. If you find a broken build, please file an issue.</p>\n<h3>Highlights</h3>\n<p>This release adds <strong>Reticulum</strong> as mesh-client's third protocol (Ratspeak sidecar, RNode flasher/BLE/Wi-Fi, triple-protocol BLE coexistence, and MeshChat UX parity). <strong>MeshCore repeater admin</strong> gains per-repeater saved passwords and more reliable RPCs. <strong>Nomad Network</strong> adds a Micron browser and large-scale mesh hardening. Packaging and CI improvements cover Flatpak, Linux arm64 cross-builds, local <code>act</code> workflows, and safer draft-release publishing.</p>\n<h3>Features</h3>\n<ul>\n<li>Reticulum third protocol — Ratspeak sidecar, MeshChat UX parity, RNode flasher/BLE/Wi-Fi, triple-protocol BLE, peer graph overhaul &amp; repo-wide i18n (Fixes #593) (#596)</li>\n<li>Nomad Micron browser, docs refresh, and large repeater book hardening (#611)</li>\n<li>Reticulum RNode selection, IPv6 connect, and quality audit hardening (#610)</li>\n<li>Reticulum export diagnostics, default TCP hubs, and MeshCore header waiting-message status (#620)</li>\n<li>Reticulum hub presets, security hardening, and packaging fixes (#621)</li>\n<li>Local act CI (container + native) and Flatpak smoke-test fix (#604)</li>\n</ul>\n<p>Also in this release: MeshCore repeater admin RPC reliability and per-repeater passwords (#614); Nomad Network UX, 10k mesh scale, CI perf, and stack hardening (#612).</p>\n<h3>Bug Fixes</h3>\n<ul>\n<li>Gate release publish on single draft GitHub release (#627)</li>\n<li>Fail tests on parseStoredJson <code>[object Object]</code> release noise (#626)</li>\n<li>MeshCore multi-hop trace priming, visible ping errors, and CI/hardening follow-ups (#625)</li>\n<li>Harden arm64 apt CI setup script for re-runs and release upgrades (#624)</li>\n<li>Stop MeshCore auto-reconnect after manual disconnect (#623)</li>\n<li>Audit follow-ups for UX, hardening, i18n, and Reticulum I2P (#622)</li>\n<li>Extract arm64 AppImages on x64 CI with unsquashfs (#619)</li>\n<li>Linux AppImage smoke test extract directory ENOENT (#618)</li>\n<li>Configure apt for Linux arm64 cross-build on Ubuntu 24.04 CI (#617)</li>\n<li>Reticulum sidecar bundling, support exports, MeshCore drain, and peers/contacts split (#616)</li>\n<li>Protocol-scoped diagnostics, language selector UX, and docs refresh (#609)</li>\n<li>Harden long MeshCore sessions against RPC races and memory growth (#608)</li>\n<li>Auto-apply rsReticulum packet-tap overlay for sidecar builds (#607)</li>\n<li>Stop Reticulum utun beacon log spam and surface Meshtastic PKI send errors (#605)</li>\n<li>Flatpak sidecar CI and actionlint installer (#603)</li>\n<li>Use dnf for Reticulum sidecar deps in Flatpak CI (#602)</li>\n<li>Flatpak Wayland launch, MeshCore queue badge, Reticulum DMs by address, and CodeQL findings (#601)</li>\n<li>Compare MeshCore firmware updates by semver, not build date (#595)</li>\n</ul>\n<h3>Other Changes</h3>\n<ul>\n<li>Generalize App orchestration for N-protocol prep (#597)</li>\n<li>N-protocol renderer prep + MeshCore multibyte path hash (#594)</li>\n<li>Consolidate timeConstants shared import for CodeQL (#615)</li>\n<li>Sync reticulum-sidecar Cargo.lock for rns-interface deps (#606)</li>\n</ul>\n<h3>Breaking Changes</h3>\n<p><em>(None)</em></p>\n<h3>Full Changelog</h3>\n<p><a href=\"https://github.com/Colorado-Mesh/mesh-client/compare/v5.20.4...v5.21.0\" target=\"_blank\" rel=\"noopener noreferrer\"><code>v5.20.4...v5.21.0</code></a></p>\n"
    },
    {
      "version": "v5.20.4",
      "name": "5.20.4",
      "datetime": "2026-06-28T20:20:23Z",
      "url": "https://github.com/Colorado-Mesh/mesh-client/releases/tag/v5.20.4",
      "prerelease": false,
      "notes": "## Highlights\r\n\r\nLessons Learned from Amateur Radio Field Day 2026. \r\n\r\nDual-protocol Noble BLE startup and reconnect get a full pass: direct connect before scan, active-protocol-first auto-connect, wake/sleep recovery, and clearer contention UX. Phantom Chat unread badges from unprogrammed or zero-PSK channels are fixed for both Meshtastic and MeshCore. Connection panel errors are humanized via i18n, and test/infra hardening covers CodeQL findings, vitest worker pools, and Vite browser dev.\r\n\r\n## Bug fixes\r\n\r\n### Noble BLE auto-connect and reconnect (#588, #591)\r\n\r\n- **Direct connect before scan:** Startup auto-connect and the reconnect card use `reconnectBleWithScan` so Noble connects via `waitForPeripheralDuringScan` instead of waiting only for renderer discovery — fixes false offline timeouts when Bluetooth is on but the saved device never appears in the scan list.\r\n- **Manual Connect opens scanner:** On macOS/Windows, manual Connect always starts Noble scanning so users can pick a different radio; reconnect to the last device uses startup auto-connect or the reconnect card.\r\n- **Timeout ownership:** Removes the ConnectionPanel 30s auto-connect timeout from Noble paths; `reconnectBleWithScan` owns wait + scan timing.\r\n- **Active-protocol-first startup (#591):** Auto-connect the last-used protocol immediately; defer the inactive protocol until the active one finishes Noble BLE configure (poll up to 30s) instead of a fixed 8s MeshCore-only stagger.\r\n- **Cross-protocol coordination:** `meshcoreNobleBleConfigureBusy` and `awaitNobleBleProtocolSettle` helpers; info banner when MeshCore auto-connect is skipped because the peripheral is shared with Meshtastic; humanized \"already in progress\" BLE errors with a dual-protocol contention hint.\r\n\r\n### Wake / sleep BLE recovery (#587, #590)\r\n\r\n- Rehydrate Meshtastic/MeshCore connection params from `lastConnection` storage on Noble disconnect and `onPowerResume`.\r\n- Stagger MeshCore power resume **8s** after Meshtastic; MeshCore BLE reconnect waits up to **30s** for Meshtastic Noble configure to settle.\r\n- Force-disconnect connecting BLE zombies and evict stale cache entries in `noble-ble-manager`; guard Meshtastic `toDevice` stream before `getWriter`.\r\n- **ConnectionPanel (macOS/Windows):** Connect retries last known BLE peripheral; macOS surfaces `macWakeRecoveryHint` for wake-related BLE failures.\r\n- **MeshCore Connect after failed auto-reconnect:** Clear stuck `bleConnectInProgressRef` on reconnect completion/exhaustion and on power resume so manual Connect works without quitting.\r\n- **Meshtastic BLE reconnect parity (#590):** Rehydrate reconnect params on Noble BLE disconnect (same pattern as MeshCore).\r\n- **Noble connecting-zombie fix (#590):** Force disconnect when peripheral is stuck in `connecting` before reconnect.\r\n- **Docs:** `docs/troubleshooting.md` — Windows sleep/wake section, updated stagger/settle timing, phantom chat unread entry.\r\n\r\n**If auto-reconnect still fails after wake (Noble):**\r\n- **macOS:** quit mesh-client (Cmd+Q) → toggle Bluetooth → reopen → wait ~5s → connect MeshCore first, then Meshtastic.\r\n- **Windows:** exit fully → toggle Bluetooth (or adapter in Device Manager) → reopen → connect MeshCore first, then Meshtastic.\r\n\r\n### Phantom Chat unread badges (#587, #590)\r\n\r\n- **Meshtastic:** Merge legacy and protocol last-read keys with `Math.max` per channel; `sanitizeMeshtasticChatLastRead`; limit App/ChatPanel unread to radio-programmed channel indices.\r\n- **MeshCore:** Limit App-level and ChatPanel unread to configured channel slots (non-zero PSK) via `meshcoreConfiguredChatChannels`; sidebar badges align with Chat channel pills from runtime channels.\r\n\r\n### Connection panel error UX (#590)\r\n\r\n- Auto-connect failures (BLE and serial) humanized via i18n; duplicate hardcoded Noble timeout hints removed from main process.\r\n- Platform detection switched from `userAgent` to `electronAPI.getPlatform()`.\r\n\r\n### Browser dev startup (#586)\r\n\r\n- No-op `electronAPI` s\n…",
      "notesHtml": "<h2>Highlights</h2>\n<p>Lessons Learned from Amateur Radio Field Day 2026. </p>\n<p>Dual-protocol Noble BLE startup and reconnect get a full pass: direct connect before scan, active-protocol-first auto-connect, wake/sleep recovery, and clearer contention UX. Phantom Chat unread badges from unprogrammed or zero-PSK channels are fixed for both Meshtastic and MeshCore. Connection panel errors are humanized via i18n, and test/infra hardening covers CodeQL findings, vitest worker pools, and Vite browser dev.</p>\n<h2>Bug fixes</h2>\n<h3>Noble BLE auto-connect and reconnect (#588, #591)</h3>\n<ul>\n<li><strong>Direct connect before scan:</strong> Startup auto-connect and the reconnect card use <code>reconnectBleWithScan</code> so Noble connects via <code>waitForPeripheralDuringScan</code> instead of waiting only for renderer discovery — fixes false offline timeouts when Bluetooth is on but the saved device never appears in the scan list.</li>\n<li><strong>Manual Connect opens scanner:</strong> On macOS/Windows, manual Connect always starts Noble scanning so users can pick a different radio; reconnect to the last device uses startup auto-connect or the reconnect card.</li>\n<li><strong>Timeout ownership:</strong> Removes the ConnectionPanel 30s auto-connect timeout from Noble paths; <code>reconnectBleWithScan</code> owns wait + scan timing.</li>\n<li><strong>Active-protocol-first startup (#591):</strong> Auto-connect the last-used protocol immediately; defer the inactive protocol until the active one finishes Noble BLE configure (poll up to 30s) instead of a fixed 8s MeshCore-only stagger.</li>\n<li><strong>Cross-protocol coordination:</strong> <code>meshcoreNobleBleConfigureBusy</code> and <code>awaitNobleBleProtocolSettle</code> helpers; info banner when MeshCore auto-connect is skipped because the peripheral is shared with Meshtastic; humanized \"already in progress\" BLE errors with a dual-protocol contention hint.</li>\n</ul>\n<h3>Wake / sleep BLE recovery (#587, #590)</h3>\n<ul>\n<li>Rehydrate Meshtastic/MeshCore connection params from <code>lastConnection</code> storage on Noble disconnect and <code>onPowerResume</code>.</li>\n<li>Stagger MeshCore power resume <strong>8s</strong> after Meshtastic; MeshCore BLE reconnect waits up to <strong>30s</strong> for Meshtastic Noble configure to settle.</li>\n<li>Force-disconnect connecting BLE zombies and evict stale cache entries in <code>noble-ble-manager</code>; guard Meshtastic <code>toDevice</code> stream before <code>getWriter</code>.</li>\n<li><strong>ConnectionPanel (macOS/Windows):</strong> Connect retries last known BLE peripheral; macOS surfaces <code>macWakeRecoveryHint</code> for wake-related BLE failures.</li>\n<li><strong>MeshCore Connect after failed auto-reconnect:</strong> Clear stuck <code>bleConnectInProgressRef</code> on reconnect completion/exhaustion and on power resume so manual Connect works without quitting.</li>\n<li><strong>Meshtastic BLE reconnect parity (#590):</strong> Rehydrate reconnect params on Noble BLE disconnect (same pattern as MeshCore).</li>\n<li><strong>Noble connecting-zombie fix (#590):</strong> Force disconnect when peripheral is stuck in <code>connecting</code> before reconnect.</li>\n<li><strong>Docs:</strong> <code>docs/troubleshooting.md</code> — Windows sleep/wake section, updated stagger/settle timing, phantom chat unread entry.</li>\n</ul>\n<p><strong>If auto-reconnect still fails after wake (Noble):</strong></p>\n<ul>\n<li><strong>macOS:</strong> quit mesh-client (Cmd+Q) → toggle Bluetooth → reopen → wait ~5s → connect MeshCore first, then Meshtastic.</li>\n<li><strong>Windows:</strong> exit fully → toggle Bluetooth (or adapter in Device Manager) → reopen → connect MeshCore first, then Meshtastic.</li>\n</ul>\n<h3>Phantom Chat unread badges (#587, #590)</h3>\n<ul>\n<li><strong>Meshtastic:</strong> Merge legacy and protocol last-read keys with <code>Math.max</code> per channel; <code>sanitizeMeshtasticChatLastRead</code>; limit App/ChatPanel unread to radio-programmed channel indices.</li>\n<li><strong>MeshCore:</strong> Limit App-level and ChatPanel unread to configured channel slots (non-zero PSK) via <code>meshcoreConfiguredChatChannels</code>; sidebar badges align with Chat channel pills from runtime channels.</li>\n</ul>\n<h3>Connection panel error UX (#590)</h3>\n<ul>\n<li>Auto-connect failures (BLE and serial) humanized via i18n; duplicate hardcoded Noble timeout hints removed from main process.</li>\n<li>Platform detection switched from <code>userAgent</code> to <code>electronAPI.getPlatform()</code>.</li>\n</ul>\n<h3>Browser dev startup (#586)</h3>\n<ul>\n<li>No-op <code>electronAPI</code> s\n…</li>\n</ul>\n"
    },
    {
      "version": "v5.20.3",
      "name": "5.20.3",
      "datetime": "2026-06-26T18:22:37Z",
      "url": "https://github.com/Colorado-Mesh/mesh-client/releases/tag/v5.20.3",
      "prerelease": false,
      "notes": "## Highlights\r\n\r\nUSB serial reconnect reliability and dual-protocol BLE coexistence are the main themes: timeouts, silence watchdogs, `SerialPort.forget()` escalation, a **Select serial port** banner when auto-reconnect is exhausted, and MeshCore deferring BLE when it would contend with Meshtastic on the same radio. Locales from recent auto-translate batches are corrected, and i18n quality checks are expanded so similar mistakes fail CI instead of shipping.\r\n\r\n## Bug fixes\r\n\r\n### USB serial reconnect on lockup and zombie ports (#583)\r\n\r\n- **Shared serial recovery** (`serialPortRecovery.ts`): **15 s** open/reconnect timeouts, `port.forget()` when supported, persisted port identity cleanup, and debounced global `navigator.serial` disconnect routing for **Meshtastic and MeshCore**.\r\n- **MeshCore USB serial**: serial watchdog (**120 s** stale / **180 s** dead), transport-loss watch on stalled streams, and last-data tracking.\r\n- **Meshtastic USB serial**: **3 min** without inbound traffic treated as a dead link.\r\n- After **5 failed** auto-reconnect attempts, sets `serialNeedsReselect` and shows a connection banner that opens **`requestPort()`** (port picker) instead of looping on `getPorts()`.\r\n- **Troubleshooting** updated with platform-neutral recovery steps for frozen / stuck \"Reconnecting…\" USB serial sessions.\r\n\r\n### Dual-protocol BLE auto-connect contention (#581)\r\n\r\n- **`meshcoreTargetsSharedMeshtasticBlePeripheral`**: when Meshtastic and MeshCore would auto-connect to the same Noble GATT peripheral, MeshCore defers BLE so Meshtastic keeps the radio.\r\n- **ConnectionPanel**: skips MeshCore Noble scan on mount, serial→BLE fallback, and device-discovered auto-connect when BLE ids match; migrates stale serial `lastConnection` to BLE before fallback.\r\n- Meshtastic connect failures now log the underlying reason in `handleRfConnectFailure`.\r\n\r\n### i18n locale quality audit (#584)\r\n\r\nFixes bad auto-translate strings from recent batches:\r\n\r\n- **es**: `porto` → `puerto` (serial port wording)\r\n- **tr**: removed `COM…` garbage in serial reselect action\r\n- **cs / id**: bare \"GIF id\" wording corrected\r\n- **it**: `stanze` → `sale` (rooms); `serialReselectAction` casing\r\n- **nl**: `maasreactie` → `mesh-reactie`\r\n- **uk**: `meshcoreReactionEmojiOption` contact vs react confusion; apostrophe spacing (`з'єднання`, `пам'ять`, etc.)\r\n- **All locales**: RSSI/SNR contact tooltip strings aligned\r\n\r\n**`check-i18n-quality`** extended with rules for `serialReselectAction`, bare GIF id hints, `meshcoreReaction` false friends, Ukrainian broken apostrophe spacing, and rooms collapse/expand hotel-room wording — plus seven regression tests.\r\n\r\n### Diagnostics docs link (#582)\r\n\r\n- **DiagnosticsPanel** Docs link now points at `docs/diagnostics.md` (stale `DIAGNOSTICS.md` path removed).\r\n- **`docLinks.test.ts`** scans UI, root markdown, `docs/`, and `.github/` for broken doc URLs and fails CI when a linked file is missing.\r\n\r\n## Infrastructure & housekeeping\r\n\r\n- **Vitest project split** (#582): `renderer-logic` (node/threads), `renderer-ui` (jsdom/forks), and `main` (node/forks) with per-project worker pools; pure lib tests skip jsdom setup overhead; coverage routing fixes restore orphaned lib tests after the split.\r\n- **`connectionStore`**: expanded selector guidance and `mirrorMqttStatusToConnection` bridge docs; cross-linked from `ConnectionDriver` and AGENTS.md.\r\n- **Vitest harness** (`vitest.harness.ts`): worker ratios and shared Vite dep inline lists extracted from magic numbers; `computeVitestMaxWorkers` validates invalid inputs.\r\n- **i18n quality script**: `localeStringQualityIssues` split into 14 focused checkers; clearer startup error when `src/renderer/locales` is missing (`MESH_CLIENT_LOCALES_DIR` override for tests).\r\n- **Shared helpers**: `docLinks.ts`, `blePairingError.ts`, `mqttVirtualNodeId.ts`, `tcpPort.ts`, and `RfConnectionTransportOpts` discriminated unions for transport-specific connect args.\r\n- **Dependency bumps**: `motion` 12.42.0, \n…",
      "notesHtml": "<h2>Highlights</h2>\n<p>USB serial reconnect reliability and dual-protocol BLE coexistence are the main themes: timeouts, silence watchdogs, <code>SerialPort.forget()</code> escalation, a <strong>Select serial port</strong> banner when auto-reconnect is exhausted, and MeshCore deferring BLE when it would contend with Meshtastic on the same radio. Locales from recent auto-translate batches are corrected, and i18n quality checks are expanded so similar mistakes fail CI instead of shipping.</p>\n<h2>Bug fixes</h2>\n<h3>USB serial reconnect on lockup and zombie ports (#583)</h3>\n<ul>\n<li><strong>Shared serial recovery</strong> (<code>serialPortRecovery.ts</code>): <strong>15 s</strong> open/reconnect timeouts, <code>port.forget()</code> when supported, persisted port identity cleanup, and debounced global <code>navigator.serial</code> disconnect routing for <strong>Meshtastic and MeshCore</strong>.</li>\n<li><strong>MeshCore USB serial</strong>: serial watchdog (<strong>120 s</strong> stale / <strong>180 s</strong> dead), transport-loss watch on stalled streams, and last-data tracking.</li>\n<li><strong>Meshtastic USB serial</strong>: <strong>3 min</strong> without inbound traffic treated as a dead link.</li>\n<li>After <strong>5 failed</strong> auto-reconnect attempts, sets <code>serialNeedsReselect</code> and shows a connection banner that opens <strong><code>requestPort()</code></strong> (port picker) instead of looping on <code>getPorts()</code>.</li>\n<li><strong>Troubleshooting</strong> updated with platform-neutral recovery steps for frozen / stuck \"Reconnecting…\" USB serial sessions.</li>\n</ul>\n<h3>Dual-protocol BLE auto-connect contention (#581)</h3>\n<ul>\n<li><strong><code>meshcoreTargetsSharedMeshtasticBlePeripheral</code></strong>: when Meshtastic and MeshCore would auto-connect to the same Noble GATT peripheral, MeshCore defers BLE so Meshtastic keeps the radio.</li>\n<li><strong>ConnectionPanel</strong>: skips MeshCore Noble scan on mount, serial→BLE fallback, and device-discovered auto-connect when BLE ids match; migrates stale serial <code>lastConnection</code> to BLE before fallback.</li>\n<li>Meshtastic connect failures now log the underlying reason in <code>handleRfConnectFailure</code>.</li>\n</ul>\n<h3>i18n locale quality audit (#584)</h3>\n<p>Fixes bad auto-translate strings from recent batches:</p>\n<ul>\n<li><strong>es</strong>: <code>porto</code> → <code>puerto</code> (serial port wording)</li>\n<li><strong>tr</strong>: removed <code>COM…</code> garbage in serial reselect action</li>\n<li><strong>cs / id</strong>: bare \"GIF id\" wording corrected</li>\n<li><strong>it</strong>: <code>stanze</code> → <code>sale</code> (rooms); <code>serialReselectAction</code> casing</li>\n<li><strong>nl</strong>: <code>maasreactie</code> → <code>mesh-reactie</code></li>\n<li><strong>uk</strong>: <code>meshcoreReactionEmojiOption</code> contact vs react confusion; apostrophe spacing (<code>з'єднання</code>, <code>пам'ять</code>, etc.)</li>\n<li><strong>All locales</strong>: RSSI/SNR contact tooltip strings aligned</li>\n</ul>\n<p><strong><code>check-i18n-quality</code></strong> extended with rules for <code>serialReselectAction</code>, bare GIF id hints, <code>meshcoreReaction</code> false friends, Ukrainian broken apostrophe spacing, and rooms collapse/expand hotel-room wording — plus seven regression tests.</p>\n<h3>Diagnostics docs link (#582)</h3>\n<ul>\n<li><strong>DiagnosticsPanel</strong> Docs link now points at <code>docs/diagnostics.md</code> (stale <code>DIAGNOSTICS.md</code> path removed).</li>\n<li><strong><code>docLinks.test.ts</code></strong> scans UI, root markdown, <code>docs/</code>, and <code>.github/</code> for broken doc URLs and fails CI when a linked file is missing.</li>\n</ul>\n<h2>Infrastructure &amp; housekeeping</h2>\n<ul>\n<li><strong>Vitest project split</strong> (#582): <code>renderer-logic</code> (node/threads), <code>renderer-ui</code> (jsdom/forks), and <code>main</code> (node/forks) with per-project worker pools; pure lib tests skip jsdom setup overhead; coverage routing fixes restore orphaned lib tests after the split.</li>\n<li><strong><code>connectionStore</code></strong>: expanded selector guidance and <code>mirrorMqttStatusToConnection</code> bridge docs; cross-linked from <code>ConnectionDriver</code> and AGENTS.md.</li>\n<li><strong>Vitest harness</strong> (<code>vitest.harness.ts</code>): worker ratios and shared Vite dep inline lists extracted from magic numbers; <code>computeVitestMaxWorkers</code> validates invalid inputs.</li>\n<li><strong>i18n quality script</strong>: <code>localeStringQualityIssues</code> split into 14 focused checkers; clearer startup error when <code>src/renderer/locales</code> is missing (<code>MESH_CLIENT_LOCALES_DIR</code> override for tests).</li>\n<li><strong>Shared helpers</strong>: <code>docLinks.ts</code>, <code>blePairingError.ts</code>, <code>mqttVirtualNodeId.ts</code>, <code>tcpPort.ts</code>, and <code>RfConnectionTransportOpts</code> discriminated unions for transport-specific connect args.</li>\n<li><strong>Dependency bumps</strong>: <code>motion</code> 12.42.0, \n…</li>\n</ul>\n"
    },
    {
      "version": "v5.20.2",
      "name": "5.20.2",
      "datetime": "2026-06-24T23:56:46Z",
      "url": "https://github.com/Colorado-Mesh/mesh-client/releases/tag/v5.20.2",
      "prerelease": false,
      "notes": "## Highlights\r\n\r\nMeshCore USB serial and Linux Web Bluetooth connect reliability is the main theme: serialized writes, ordered init RPCs, and full channel enumeration before post-connect setup. Chat reaction capture after the OS emoji picker is fixed on all platforms. Header layout no longer overlaps at narrow widths, and protocol-switcher unread badges meet WCAG contrast.\r\n\r\n## Bug fixes\r\n\r\n### Header layout (#575)\r\n- Restructured the banner as a two-column grid so the protocol switcher and status cluster no longer paint on top of each other at minimum width.\r\n- Hides TAK/MQTT/connection text below `lg` and the node label below `xl`; icons, badges, and `aria-label`/`title` tooltips preserve context when labels are hidden.\r\n\r\n### MeshCore USB serial connect (#576, #578, #579)\r\n- **Serialized Web Serial writes** via `createSerializedWritableStream` so concurrent init RPCs no longer hit `WritableStream is locked` or stall `getContacts` (60s timeouts on macOS/Windows USB companion).\r\n- **Sequential init handshake** on USB serial and Linux Web Bluetooth: `getSelfInfo` → `getContacts` → `getChannels` before `syncDeviceTime`, auto-add, and `setAdvertLatLong`. TCP and Noble BLE keep parallel overlap for speed.\r\n- **Graceful auto-add GET**: unsupported `Err` and silent firmware treated as non-fatal skips instead of connect timeouts.\r\n- **Stale port cleanup**: closes leftover Web Serial ports on first `connectSerial()`, not only on reconnect.\r\n- **Companion TX echo filter** extended to USB serial (`DeviceQuery` echo code 22), shared with Noble IPC.\r\n\r\n### MeshCore Linux Web Bluetooth (#579)\r\n- Serializes `toDevice` writes during connect-time RPCs (same pattern as USB serial).\r\n- PopOS / reconnect paths get reliable full channel lists instead of public-only partial enumeration.\r\n\r\n### Chat reactions after emoji picker (#577, #578)\r\n- Typing after closing the OS emoji panel no longer sends keystrokes as tapback reactions (e.g. typing “joey” → `j`/`o`/`e` reactions).\r\n- Explicit reaction capture lifecycle: `clearReactionCapture()` on react/dismiss/Escape; `reactionCapturePendingRef` gates Linux click and native hidden-input handlers.\r\n- macOS/Windows: printable keys redirected to the composer; `isReactionPickerEmojiGlyph` rejects plain ASCII letters.\r\n- Clears stale capture on window focus; clears `replyTo` when opening React.\r\n\r\n## Accessibility\r\n\r\n- **Readable green contrast**: darkened to `#15803d` so white-on-green protocol-switcher badges pass WCAG AA 4.5:1; migrates persisted `#16a34a` overrides on load.\r\n- **`ProtocolUnreadBadge`**: decorative `animate-pulse` on an `aria-hidden` layer; text label stays fully opaque for contrast.\r\n- **`hydrateAxeThemeColors`** test helper; expanded vitest-axe coverage for Meshtastic/MeshCore unread badges and App header.\r\n\r\n## Infrastructure & housekeeping\r\n\r\n- Dependency bumps: Electron **41.8 → 41.9**, Vite 8.1, TypeScript ESLint 8.62, `@axe-core/react` 4.12, and others; Flatpak vendored Electron archives synced.\r\n- MeshCore timing constants centralized in `timeConstants.ts` (dual-Noble BLE, Web Bluetooth, reconnect backoff cap).\r\n- Shared time constants: `MS_PER_HOUR` / `MS_PER_DAY` derived from base units; `MS_PER_YEAR` documented as non-leap approximation.\r\n- Timestamp skew tests expanded; ChatPanel imports aligned to shared `messageTimestampSkew` / `timeConstants` modules.\r\n- AGENTS.md: platform parity defaults, pulse-split badge pattern, axe testing guidance.\r\n\r\n## Breaking changes\r\n\r\n*(None)*\r\n\r\n**Full Changelog**: https://github.com/Colorado-Mesh/mesh-client/compare/v5.20.1...v5.20.2",
      "notesHtml": "<h2>Highlights</h2>\n<p>MeshCore USB serial and Linux Web Bluetooth connect reliability is the main theme: serialized writes, ordered init RPCs, and full channel enumeration before post-connect setup. Chat reaction capture after the OS emoji picker is fixed on all platforms. Header layout no longer overlaps at narrow widths, and protocol-switcher unread badges meet WCAG contrast.</p>\n<h2>Bug fixes</h2>\n<h3>Header layout (#575)</h3>\n<ul>\n<li>Restructured the banner as a two-column grid so the protocol switcher and status cluster no longer paint on top of each other at minimum width.</li>\n<li>Hides TAK/MQTT/connection text below <code>lg</code> and the node label below <code>xl</code>; icons, badges, and <code>aria-label</code>/<code>title</code> tooltips preserve context when labels are hidden.</li>\n</ul>\n<h3>MeshCore USB serial connect (#576, #578, #579)</h3>\n<ul>\n<li><strong>Serialized Web Serial writes</strong> via <code>createSerializedWritableStream</code> so concurrent init RPCs no longer hit <code>WritableStream is locked</code> or stall <code>getContacts</code> (60s timeouts on macOS/Windows USB companion).</li>\n<li><strong>Sequential init handshake</strong> on USB serial and Linux Web Bluetooth: <code>getSelfInfo</code> → <code>getContacts</code> → <code>getChannels</code> before <code>syncDeviceTime</code>, auto-add, and <code>setAdvertLatLong</code>. TCP and Noble BLE keep parallel overlap for speed.</li>\n<li><strong>Graceful auto-add GET</strong>: unsupported <code>Err</code> and silent firmware treated as non-fatal skips instead of connect timeouts.</li>\n<li><strong>Stale port cleanup</strong>: closes leftover Web Serial ports on first <code>connectSerial()</code>, not only on reconnect.</li>\n<li><strong>Companion TX echo filter</strong> extended to USB serial (<code>DeviceQuery</code> echo code 22), shared with Noble IPC.</li>\n</ul>\n<h3>MeshCore Linux Web Bluetooth (#579)</h3>\n<ul>\n<li>Serializes <code>toDevice</code> writes during connect-time RPCs (same pattern as USB serial).</li>\n<li>PopOS / reconnect paths get reliable full channel lists instead of public-only partial enumeration.</li>\n</ul>\n<h3>Chat reactions after emoji picker (#577, #578)</h3>\n<ul>\n<li>Typing after closing the OS emoji panel no longer sends keystrokes as tapback reactions (e.g. typing “joey” → <code>j</code>/<code>o</code>/<code>e</code> reactions).</li>\n<li>Explicit reaction capture lifecycle: <code>clearReactionCapture()</code> on react/dismiss/Escape; <code>reactionCapturePendingRef</code> gates Linux click and native hidden-input handlers.</li>\n<li>macOS/Windows: printable keys redirected to the composer; <code>isReactionPickerEmojiGlyph</code> rejects plain ASCII letters.</li>\n<li>Clears stale capture on window focus; clears <code>replyTo</code> when opening React.</li>\n</ul>\n<h2>Accessibility</h2>\n<ul>\n<li><strong>Readable green contrast</strong>: darkened to <code>#15803d</code> so white-on-green protocol-switcher badges pass WCAG AA 4.5:1; migrates persisted <code>#16a34a</code> overrides on load.</li>\n<li><strong><code>ProtocolUnreadBadge</code></strong>: decorative <code>animate-pulse</code> on an <code>aria-hidden</code> layer; text label stays fully opaque for contrast.</li>\n<li><strong><code>hydrateAxeThemeColors</code></strong> test helper; expanded vitest-axe coverage for Meshtastic/MeshCore unread badges and App header.</li>\n</ul>\n<h2>Infrastructure &amp; housekeeping</h2>\n<ul>\n<li>Dependency bumps: Electron <strong>41.8 → 41.9</strong>, Vite 8.1, TypeScript ESLint 8.62, <code>@axe-core/react</code> 4.12, and others; Flatpak vendored Electron archives synced.</li>\n<li>MeshCore timing constants centralized in <code>timeConstants.ts</code> (dual-Noble BLE, Web Bluetooth, reconnect backoff cap).</li>\n<li>Shared time constants: <code>MS_PER_HOUR</code> / <code>MS_PER_DAY</code> derived from base units; <code>MS_PER_YEAR</code> documented as non-leap approximation.</li>\n<li>Timestamp skew tests expanded; ChatPanel imports aligned to shared <code>messageTimestampSkew</code> / <code>timeConstants</code> modules.</li>\n<li>AGENTS.md: platform parity defaults, pulse-split badge pattern, axe testing guidance.</li>\n</ul>\n<h2>Breaking changes</h2>\n<p><em>(None)</em></p>\n<p><strong>Full Changelog</strong>: <a href=\"https://github.com/Colorado-Mesh/mesh-client/compare/v5.20.1...v5.20.2\" target=\"_blank\" rel=\"noopener noreferrer\">https://github.com/Colorado-Mesh/mesh-client/compare/v5.20.1...v5.20.2</a></p>\n"
    },
    {
      "version": "v5.20.1",
      "name": "5.20.1",
      "datetime": "2026-06-21T14:57:41Z",
      "url": "https://github.com/Colorado-Mesh/mesh-client/releases/tag/v5.20.1",
      "prerelease": false,
      "notes": "## Highlights\r\n\r\nMeshCore interop and Rooms UX catch up with Chat: companion-style keyless tapbacks/replies by default, optional **MeshCore Open wire compatibility** for keyed replies, Open reactions, and GIF send, plus Rooms toolbar parity (search, export, mute, collapse). Channel unread badges recover from RTC-skew poison traffic, and releases stay **draft** until a maintainer publishes them.\r\n\r\n## Features\r\n\r\n### MeshCore Open wire compatibility (#568)\r\n- New **App → MeshCore → Open wire compatibility** toggle (default **off**, marked experimental).\r\n- When enabled: keyed text replies (`@[Name#key]`), Open `r:HASH:INDEX` reactions (tapback fallback), and outbound `g:GIFID` GIF send via Chat GIF modal.\r\n- Default remains companion keyless `@[Name]` replies and tapbacks for official app / Discord bridge parity.\r\n\r\n### Rooms panel parity (#566)\r\n- In-panel **search** with highlight, **export**, **jump-to-date**, **per-room mute**, day separators, **compact mode**, sender filter, and **collapsible room list** (localStorage).\r\n- Muted `room:*` views excluded from sidebar/tab unread counts; App notified on mute changes.\r\n- Collapsed rail shows 2-letter room initials, auth status dot, and green selection border (no broken login-all control).\r\n\r\n### Chat & media (#566)\r\n- **Clear search filter** when Chat search is closed (toggle, Escape, ×).\r\n- Inbound MeshCore Open **`g:GIFID`** wire renders inline Giphy GIFs in chat (with page link fallback).\r\n\r\n## Bug fixes\r\n\r\n### MeshCore tapbacks & reactions (#494, #565, #566, #567, #569)\r\n- Outbound reactions use keyless **`@[Name] emoji`** companion wire (not `@[Name#timestamp]`, which leaked into Discord/MQTT bridges).\r\n- Local chat still shows reaction **badges**; `replyId` kept for dedup without keyed wire.\r\n- Inbound emoji-only replies promoted to tapbacks; wider **10 min** echo dedup with sec/ms `replyId` matching.\r\n- RF replay dedup and UI dedupe stop stacking optimistic + echo rows (#494).\r\n- Inbound Open **`r:HASH:INDEX`** reactions parsed; outbound Open wire removed in favor of companion format.\r\n\r\n### MeshCore reply threading & quotes (#568)\r\n- Outbound channel/DM replies prefixed on wire via shared `buildMeshcoreOutboundSendText()` (fixes plain-text sends after Protocol migration).\r\n- Parent lookup matches firmware **seconds vs client ms** keys; explicit `#key` no longer falls back to “latest from sender.”\r\n- Default text replies use keyless `@[Name]` wire; keyed prefix retained for inbound wire from other clients.\r\n\r\n### Channel unread badges (#568, #569)\r\n- Unread counting aligned with mark-read using `effectiveMessageTimestampMs` and clamped watermarks.\r\n- Future-dated / poison traffic no longer inflates `ch:N` last-read; timestamps clamped at ingest, DB save/load, and hydration.\r\n- **Copy Debug Snapshot** extended with last-read triage fields for badge debugging.\r\n\r\n### Rooms scroll (#566, #568, #569)\r\n- Fixes race where pinned-bottom scroll clobbered **Go to message** / Starred jumps on room switch.\r\n- Skips live-append scroll while `scrollToRowKey` or suppress flags are active.\r\n\r\n### Timestamps & room login (#570, #571)\r\n- Explicit `<= 0` guards in `messageTimestampSkew` (zero = missing timestamp / no watermark, not Unix epoch).\r\n- Hop-scaled MeshCore room login timeouts extracted to named constants in `timeConstants.ts`.\r\n\r\n## Infrastructure & housekeeping\r\n- **GitHub releases stay draft** until manual publish (#564) — `electron-builder` + Flatpak workflow + docs updated.\r\n- `release.sh`: single git-log pass, correct `feat!:` breaking detection, annotated tags.\r\n- CodeQL hardening: Giphy URL hostname parsing, dead-code cleanup, MeshCore runtime naming/constants.\r\n- Docs: reply misquote cause, room BBS wire vs chat, AGENTS/troubleshooting/parity updates.\r\n\r\n## Breaking changes\r\n*(None)*\r\n\r\n**Full Changelog**: https://github.com/Colorado-Mesh/mesh-client/compare/v5.20.0...v5.20.1",
      "notesHtml": "<h2>Highlights</h2>\n<p>MeshCore interop and Rooms UX catch up with Chat: companion-style keyless tapbacks/replies by default, optional <strong>MeshCore Open wire compatibility</strong> for keyed replies, Open reactions, and GIF send, plus Rooms toolbar parity (search, export, mute, collapse). Channel unread badges recover from RTC-skew poison traffic, and releases stay <strong>draft</strong> until a maintainer publishes them.</p>\n<h2>Features</h2>\n<h3>MeshCore Open wire compatibility (#568)</h3>\n<ul>\n<li>New <strong>App → MeshCore → Open wire compatibility</strong> toggle (default <strong>off</strong>, marked experimental).</li>\n<li>When enabled: keyed text replies (<code>@[Name#key]</code>), Open <code>r:HASH:INDEX</code> reactions (tapback fallback), and outbound <code>g:GIFID</code> GIF send via Chat GIF modal.</li>\n<li>Default remains companion keyless <code>@[Name]</code> replies and tapbacks for official app / Discord bridge parity.</li>\n</ul>\n<h3>Rooms panel parity (#566)</h3>\n<ul>\n<li>In-panel <strong>search</strong> with highlight, <strong>export</strong>, <strong>jump-to-date</strong>, <strong>per-room mute</strong>, day separators, <strong>compact mode</strong>, sender filter, and <strong>collapsible room list</strong> (localStorage).</li>\n<li>Muted <code>room:*</code> views excluded from sidebar/tab unread counts; App notified on mute changes.</li>\n<li>Collapsed rail shows 2-letter room initials, auth status dot, and green selection border (no broken login-all control).</li>\n</ul>\n<h3>Chat &amp; media (#566)</h3>\n<ul>\n<li><strong>Clear search filter</strong> when Chat search is closed (toggle, Escape, ×).</li>\n<li>Inbound MeshCore Open <strong><code>g:GIFID</code></strong> wire renders inline Giphy GIFs in chat (with page link fallback).</li>\n</ul>\n<h2>Bug fixes</h2>\n<h3>MeshCore tapbacks &amp; reactions (#494, #565, #566, #567, #569)</h3>\n<ul>\n<li>Outbound reactions use keyless <strong><code>@[Name] emoji</code></strong> companion wire (not <code>@[Name#timestamp]</code>, which leaked into Discord/MQTT bridges).</li>\n<li>Local chat still shows reaction <strong>badges</strong>; <code>replyId</code> kept for dedup without keyed wire.</li>\n<li>Inbound emoji-only replies promoted to tapbacks; wider <strong>10 min</strong> echo dedup with sec/ms <code>replyId</code> matching.</li>\n<li>RF replay dedup and UI dedupe stop stacking optimistic + echo rows (#494).</li>\n<li>Inbound Open <strong><code>r:HASH:INDEX</code></strong> reactions parsed; outbound Open wire removed in favor of companion format.</li>\n</ul>\n<h3>MeshCore reply threading &amp; quotes (#568)</h3>\n<ul>\n<li>Outbound channel/DM replies prefixed on wire via shared <code>buildMeshcoreOutboundSendText()</code> (fixes plain-text sends after Protocol migration).</li>\n<li>Parent lookup matches firmware <strong>seconds vs client ms</strong> keys; explicit <code>#key</code> no longer falls back to “latest from sender.”</li>\n<li>Default text replies use keyless <code>@[Name]</code> wire; keyed prefix retained for inbound wire from other clients.</li>\n</ul>\n<h3>Channel unread badges (#568, #569)</h3>\n<ul>\n<li>Unread counting aligned with mark-read using <code>effectiveMessageTimestampMs</code> and clamped watermarks.</li>\n<li>Future-dated / poison traffic no longer inflates <code>ch:N</code> last-read; timestamps clamped at ingest, DB save/load, and hydration.</li>\n<li><strong>Copy Debug Snapshot</strong> extended with last-read triage fields for badge debugging.</li>\n</ul>\n<h3>Rooms scroll (#566, #568, #569)</h3>\n<ul>\n<li>Fixes race where pinned-bottom scroll clobbered <strong>Go to message</strong> / Starred jumps on room switch.</li>\n<li>Skips live-append scroll while <code>scrollToRowKey</code> or suppress flags are active.</li>\n</ul>\n<h3>Timestamps &amp; room login (#570, #571)</h3>\n<ul>\n<li>Explicit <code>&lt;= 0</code> guards in <code>messageTimestampSkew</code> (zero = missing timestamp / no watermark, not Unix epoch).</li>\n<li>Hop-scaled MeshCore room login timeouts extracted to named constants in <code>timeConstants.ts</code>.</li>\n</ul>\n<h2>Infrastructure &amp; housekeeping</h2>\n<ul>\n<li><strong>GitHub releases stay draft</strong> until manual publish (#564) — <code>electron-builder</code> + Flatpak workflow + docs updated.</li>\n<li><code>release.sh</code>: single git-log pass, correct <code>feat!:</code> breaking detection, annotated tags.</li>\n<li>CodeQL hardening: Giphy URL hostname parsing, dead-code cleanup, MeshCore runtime naming/constants.</li>\n<li>Docs: reply misquote cause, room BBS wire vs chat, AGENTS/troubleshooting/parity updates.</li>\n</ul>\n<h2>Breaking changes</h2>\n<p><em>(None)</em></p>\n<p><strong>Full Changelog</strong>: <a href=\"https://github.com/Colorado-Mesh/mesh-client/compare/v5.20.0...v5.20.1\" target=\"_blank\" rel=\"noopener noreferrer\">https://github.com/Colorado-Mesh/mesh-client/compare/v5.20.0...v5.20.1</a></p>\n"
    },
    {
      "version": "v5.20.0",
      "name": "5.20.0",
      "datetime": "2026-06-19T21:46:06Z",
      "url": "https://github.com/Colorado-Mesh/mesh-client/releases/tag/v5.20.0",
      "prerelease": false,
      "notes": "## Highlights\n\nA major reliability and parity release: virtualized chat scroll is stable on Windows/Linux, Windows on ARM gets dedicated installers and CI smoke tests, Meshtastic/MeshCore feature gaps close (MQTT proxy gateway, per-node key backup, flood scope), and identity-scoped stores no longer leave chat stuck after reconnect.\n\n## Features\n\n### Per-node key backup (#520, #521)\n- Encrypted backup/restore for **full public + private key pairs**, indexed per Meshtastic `nodeNum` and MeshCore `nodeId` (replaces single app-wide Meshtastic slot).\n- Shared **Key Backup / Restore** UI with **Restore from backup…** picker for factory reset / node-id changes; legacy `mesh-client:key-backup` migrates on first Security tab open.\n- MeshCore Security tab enabled for backup/restore, sign, export/import; restore syncs active MQTT identity.\n\n### Meshtastic / MeshCore parity (#532)\n- **Meshtastic MQTT proxy gateway** — `MqttClientProxyMessage` bridge over local radio, broker `publishProxy` IPC, module-config auto-connect, Map Report module section, XMODEM on Radio tab, module debug status panels.\n- **MeshCore parity** — Regional flood scope (collapsible Radio section), TX Power with firmware max clamp, zero-hop advert + App auto-flood type, waiting-messages Chat badge, Sniffer transport/route legend.\n- **Remote-admin UI gating** — Hide local-only controls (XMODEM, MQTT proxy hint, DFU/OTA/factory reset) when **Configure node** targets a remote radio.\n- **Sniffer expand-row parity** — Meshtastic Raw Packet Log rows show legend hints and decoded `MeshPacket` details above hex, matching MeshCore.\n- **Chat transport badges** — Hybrid RF+MQTT messages show Wi‑Fi and globe icons side-by-side.\n\n### UI & notifications (#522, #542, #549)\n- **Animated Lucide icons** (~140 inline SVGs → `lucide-react-motion`) with shared icon modules; **App → Appearance → Reduce motion** toggle suppresses decorative animation while keeping functional spinners and connection pulses.\n- **Identity-aware boot sequence** — Terminal-style splash on connect reflecting active identity, hardware, channels, and node sync before the protocol one-liner.\n- **Typed chat notification sounds** — Channel = single 880 Hz pulse; DM/reply = dual-tone chord; batch priority reply > dm > channel; App vs ChatPanel split avoids double beeps when backgrounded.\n\n### MeshCore UX (#531)\n- Contact offload progress UI with cancel support during save/remove/reconcile.\n- RSSI/SNR metrics in node list and detail panel (capability-gated).\n- Rooms panel compact header toolbar; **Log in all** only targets rooms with saved passwords; per-view mute respected for background toasts/sounds.\n\n## Bug fixes\n\n### Chat scroll & virtualization (#535, #537, #539, #545–#547, #552, #562)\n- TanStack Virtual end-anchored chat/rooms with shared `chatScrollUtils` helpers; fixes Windows/Linux wheel jitter, unread-divider snap, virtual row overlap, and tab-return scroll jumps.\n- ResizeObserver 0×0 measurements on hidden tabs no longer corrupt row height cache.\n- Decoupled virtualizer scroll-end threshold (30px) from UI pin threshold (200px) to stop Windows bounce after dynamic content grows.\n- Scroll position restored on tab re-entry; pinned-to-bottom auto-scroll preserved.\n\n### Identity & data integrity (#544, #561)\n- Startup DB repairs: stuck MeshCore room `sending` rows, orphan duplicates, MeshCore contact labels purged from Meshtastic node table, null inbound message status set to `acked`.\n- **Stuck chat after reconnect** — Live ingress vs offline identity bucket mismatch fixed; offline store slices merge on connect; **Copy Debug Snapshot** in App panel for support.\n- Meshtastic ingest skips saving MeshCore contact-type labels; shared `meshcoreContactHwLabels` constants.\n\n### Windows packaging (#519, #534, #538, #550, #555–#560)\n- **Separate x64 and arm64 NSIS installers** (`Mesh-client Setup {version}.exe` and `-arm64.exe`) instead of broken universal installer.\n- NSIS payloads switched from 7z to **zip** for reliable\n…",
      "notesHtml": "<h2>Highlights</h2>\n<p>A major reliability and parity release: virtualized chat scroll is stable on Windows/Linux, Windows on ARM gets dedicated installers and CI smoke tests, Meshtastic/MeshCore feature gaps close (MQTT proxy gateway, per-node key backup, flood scope), and identity-scoped stores no longer leave chat stuck after reconnect.</p>\n<h2>Features</h2>\n<h3>Per-node key backup (#520, #521)</h3>\n<ul>\n<li>Encrypted backup/restore for <strong>full public + private key pairs</strong>, indexed per Meshtastic <code>nodeNum</code> and MeshCore <code>nodeId</code> (replaces single app-wide Meshtastic slot).</li>\n<li>Shared <strong>Key Backup / Restore</strong> UI with <strong>Restore from backup…</strong> picker for factory reset / node-id changes; legacy <code>mesh-client:key-backup</code> migrates on first Security tab open.</li>\n<li>MeshCore Security tab enabled for backup/restore, sign, export/import; restore syncs active MQTT identity.</li>\n</ul>\n<h3>Meshtastic / MeshCore parity (#532)</h3>\n<ul>\n<li><strong>Meshtastic MQTT proxy gateway</strong> — <code>MqttClientProxyMessage</code> bridge over local radio, broker <code>publishProxy</code> IPC, module-config auto-connect, Map Report module section, XMODEM on Radio tab, module debug status panels.</li>\n<li><strong>MeshCore parity</strong> — Regional flood scope (collapsible Radio section), TX Power with firmware max clamp, zero-hop advert + App auto-flood type, waiting-messages Chat badge, Sniffer transport/route legend.</li>\n<li><strong>Remote-admin UI gating</strong> — Hide local-only controls (XMODEM, MQTT proxy hint, DFU/OTA/factory reset) when <strong>Configure node</strong> targets a remote radio.</li>\n<li><strong>Sniffer expand-row parity</strong> — Meshtastic Raw Packet Log rows show legend hints and decoded <code>MeshPacket</code> details above hex, matching MeshCore.</li>\n<li><strong>Chat transport badges</strong> — Hybrid RF+MQTT messages show Wi‑Fi and globe icons side-by-side.</li>\n</ul>\n<h3>UI &amp; notifications (#522, #542, #549)</h3>\n<ul>\n<li><strong>Animated Lucide icons</strong> (~140 inline SVGs → <code>lucide-react-motion</code>) with shared icon modules; <strong>App → Appearance → Reduce motion</strong> toggle suppresses decorative animation while keeping functional spinners and connection pulses.</li>\n<li><strong>Identity-aware boot sequence</strong> — Terminal-style splash on connect reflecting active identity, hardware, channels, and node sync before the protocol one-liner.</li>\n<li><strong>Typed chat notification sounds</strong> — Channel = single 880 Hz pulse; DM/reply = dual-tone chord; batch priority reply &gt; dm &gt; channel; App vs ChatPanel split avoids double beeps when backgrounded.</li>\n</ul>\n<h3>MeshCore UX (#531)</h3>\n<ul>\n<li>Contact offload progress UI with cancel support during save/remove/reconcile.</li>\n<li>RSSI/SNR metrics in node list and detail panel (capability-gated).</li>\n<li>Rooms panel compact header toolbar; <strong>Log in all</strong> only targets rooms with saved passwords; per-view mute respected for background toasts/sounds.</li>\n</ul>\n<h2>Bug fixes</h2>\n<h3>Chat scroll &amp; virtualization (#535, #537, #539, #545–#547, #552, #562)</h3>\n<ul>\n<li>TanStack Virtual end-anchored chat/rooms with shared <code>chatScrollUtils</code> helpers; fixes Windows/Linux wheel jitter, unread-divider snap, virtual row overlap, and tab-return scroll jumps.</li>\n<li>ResizeObserver 0×0 measurements on hidden tabs no longer corrupt row height cache.</li>\n<li>Decoupled virtualizer scroll-end threshold (30px) from UI pin threshold (200px) to stop Windows bounce after dynamic content grows.</li>\n<li>Scroll position restored on tab re-entry; pinned-to-bottom auto-scroll preserved.</li>\n</ul>\n<h3>Identity &amp; data integrity (#544, #561)</h3>\n<ul>\n<li>Startup DB repairs: stuck MeshCore room <code>sending</code> rows, orphan duplicates, MeshCore contact labels purged from Meshtastic node table, null inbound message status set to <code>acked</code>.</li>\n<li><strong>Stuck chat after reconnect</strong> — Live ingress vs offline identity bucket mismatch fixed; offline store slices merge on connect; <strong>Copy Debug Snapshot</strong> in App panel for support.</li>\n<li>Meshtastic ingest skips saving MeshCore contact-type labels; shared <code>meshcoreContactHwLabels</code> constants.</li>\n</ul>\n<h3>Windows packaging (#519, #534, #538, #550, #555–#560)</h3>\n<ul>\n<li><strong>Separate x64 and arm64 NSIS installers</strong> (<code>Mesh-client Setup {version}.exe</code> and <code>-arm64.exe</code>) instead of broken universal installer.</li>\n<li>NSIS payloads switched from 7z to <strong>zip</strong> for reliable\n…</li>\n</ul>\n"
    },
    {
      "version": "v5.19.3",
      "name": "5.19.3",
      "datetime": "2026-06-06T17:20:02Z",
      "url": "https://github.com/Colorado-Mesh/mesh-client/releases/tag/v5.19.3",
      "prerelease": false,
      "notes": "## Highlights\r\nA reliability-focused patch from the dual-protocol audit: MeshCore DMs no longer bleed into wrong tabs or phantom contacts, Meshtastic BLE and MQTT sessions are more stable, and chat/security hardening lands across the stack (virtualized chat, coordinated shutdown, SSRF guard on link previews).\r\n\r\n## MeshCore\r\n* DM sender resolution (#507) — Prefix maps seed from the global pubkey registry on subscribe; SQLite contacts pre-load before ingress so live/queued DMs resolve to the correct peer immediately instead of collapsing under a shared Unknown stub or sender_id 0.\r\n* Contact & protocol safety (#509) — Clear per-subscription prefix lookup maps on unsubscribe; mergeNode keeps the bucket nodeId over conflicting patches; batch slice totals reject non-integers; clearer error when DM send lacks destination pubkey.\r\n* Chat pathway hardening (#508) — Channel send throws when no RF/MQTT transport; pubkey 6-byte prefix collision detection; repair sender_id=0 rows after contact sync; tighter wire reply-key regex.\r\n* Rooms sidebar markers (#508) — Green-filled dot = active session; sky-blue half-circle = saved password but not logged in; status legend, header session badge, and clearer tooltips. i18n fixes across 15 locales for marker strings and false-friend “leave space” translations.\r\n\r\n## Meshtastic\r\n* BLE transport serialization (#511) — Serialized toDevice wrapper now applied on Noble BLE (was serial-only), preventing SDK heartbeat pings from racing Store & Forward writes and locking WritableStream.\r\n* MQTT auto-connect (#510) — Honors auto-launch when switching back to the Meshtastic tab; treats autoLaunch as explicit opt-in so MeshCore tab no longer silently skips or tears down an opted-in MQTT session.\r\n* MQTT decrypt reliability (#513) — Rejects false-positive decrypt candidates (wrong PSKs that still parse as protobuf) so key search continues to the correct channel/publish-time PSK; fixes intermittent CI broker-echo failures (~1.8% decoy rate with DEFAULT_PSK).\r\n* Chat & ingest (#508) — Normalized MQTT chat ingest (broadcast to, dedup fields, \"0\" payload guard); composite seenPacketIds key; S&F replay content dedup; chat export correctly labels broadcast messages as channel (not DM); cross-transport dedup uses outbound receivedVia + store-backed RF scans; Store & Forward empty-text handling hardened.\r\n* Diagnostics & PSK (#508) — Split incremental vs full reanalysis debounce timers so they no longer cancel each other; channel URL PSK bytes normalized (empty → default public key, short keys zero-padded to 16 bytes); short named MQTT lines like HamNet= parse as named empty values.\r\n\r\n## UI\r\n* MQTT path icons (#510) — Globe icon changed from purple to sky so it no longer reads like stale-node legend color; lone MQTT-only globes centered in the nodes column; hybrid rows still show RF + globe as a pair; chat transport badge color aligned.\r\n\r\n## Security & reliability\r\n* Coordinated shutdown (#508) — Flush logs, stop TAK/MQTT, close SQLite with dbClosed guard to block late IPC reopen.\r\n* Link preview SSRF (#508) — Block proxied og:image redirects to private/localhost targets.\r\n* Input validation (#508) — Reject negative MeshCore MQTT senderNodeId; node hex search so query \"0\" no longer matches every node.\r\n* Shared helpers (#508) — Hardened PSK line/URL parsing, contact age cutoff, reaction emoji BMP, correlation suffix.\r\n\r\n## Performance & infrastructure\r\n* Virtualized chat (#508) — ChatPanel messages use @tanstack/react-virtual; MeshCore dedupe O(1) index.\r\n* Notifications (#508) — Reuse single AudioContext instead of creating one per beep.\r\n* TAK (#508) — Cap clients at 16 with 24h idle timeout; async cert writes.\r\n* Lint & types (#508) — Re-enabled no-unsafe-* rules for src/shared/**; typed protobuf boundary via meshtasticProtobufSchemas.ts; tsconfig.strict.json for incremental shared strictness.\r\n* CI scripts (#508) — GPIO brand check, IPC contract scan scope, log-injection arg detection, document.write XSS check\n…",
      "notesHtml": "<h2>Highlights</h2>\n<p>A reliability-focused patch from the dual-protocol audit: MeshCore DMs no longer bleed into wrong tabs or phantom contacts, Meshtastic BLE and MQTT sessions are more stable, and chat/security hardening lands across the stack (virtualized chat, coordinated shutdown, SSRF guard on link previews).</p>\n<h2>MeshCore</h2>\n<ul>\n<li>DM sender resolution (#507) — Prefix maps seed from the global pubkey registry on subscribe; SQLite contacts pre-load before ingress so live/queued DMs resolve to the correct peer immediately instead of collapsing under a shared Unknown stub or sender_id 0.</li>\n<li>Contact &amp; protocol safety (#509) — Clear per-subscription prefix lookup maps on unsubscribe; mergeNode keeps the bucket nodeId over conflicting patches; batch slice totals reject non-integers; clearer error when DM send lacks destination pubkey.</li>\n<li>Chat pathway hardening (#508) — Channel send throws when no RF/MQTT transport; pubkey 6-byte prefix collision detection; repair sender_id=0 rows after contact sync; tighter wire reply-key regex.</li>\n<li>Rooms sidebar markers (#508) — Green-filled dot = active session; sky-blue half-circle = saved password but not logged in; status legend, header session badge, and clearer tooltips. i18n fixes across 15 locales for marker strings and false-friend “leave space” translations.</li>\n</ul>\n<h2>Meshtastic</h2>\n<ul>\n<li>BLE transport serialization (#511) — Serialized toDevice wrapper now applied on Noble BLE (was serial-only), preventing SDK heartbeat pings from racing Store &amp; Forward writes and locking WritableStream.</li>\n<li>MQTT auto-connect (#510) — Honors auto-launch when switching back to the Meshtastic tab; treats autoLaunch as explicit opt-in so MeshCore tab no longer silently skips or tears down an opted-in MQTT session.</li>\n<li>MQTT decrypt reliability (#513) — Rejects false-positive decrypt candidates (wrong PSKs that still parse as protobuf) so key search continues to the correct channel/publish-time PSK; fixes intermittent CI broker-echo failures (~1.8% decoy rate with DEFAULT_PSK).</li>\n<li>Chat &amp; ingest (#508) — Normalized MQTT chat ingest (broadcast to, dedup fields, \"0\" payload guard); composite seenPacketIds key; S&amp;F replay content dedup; chat export correctly labels broadcast messages as channel (not DM); cross-transport dedup uses outbound receivedVia + store-backed RF scans; Store &amp; Forward empty-text handling hardened.</li>\n<li>Diagnostics &amp; PSK (#508) — Split incremental vs full reanalysis debounce timers so they no longer cancel each other; channel URL PSK bytes normalized (empty → default public key, short keys zero-padded to 16 bytes); short named MQTT lines like HamNet= parse as named empty values.</li>\n</ul>\n<h2>UI</h2>\n<ul>\n<li>MQTT path icons (#510) — Globe icon changed from purple to sky so it no longer reads like stale-node legend color; lone MQTT-only globes centered in the nodes column; hybrid rows still show RF + globe as a pair; chat transport badge color aligned.</li>\n</ul>\n<h2>Security &amp; reliability</h2>\n<ul>\n<li>Coordinated shutdown (#508) — Flush logs, stop TAK/MQTT, close SQLite with dbClosed guard to block late IPC reopen.</li>\n<li>Link preview SSRF (#508) — Block proxied og:image redirects to private/localhost targets.</li>\n<li>Input validation (#508) — Reject negative MeshCore MQTT senderNodeId; node hex search so query \"0\" no longer matches every node.</li>\n<li>Shared helpers (#508) — Hardened PSK line/URL parsing, contact age cutoff, reaction emoji BMP, correlation suffix.</li>\n</ul>\n<h2>Performance &amp; infrastructure</h2>\n<ul>\n<li>Virtualized chat (#508) — ChatPanel messages use @tanstack/react-virtual; MeshCore dedupe O(1) index.</li>\n<li>Notifications (#508) — Reuse single AudioContext instead of creating one per beep.</li>\n<li>TAK (#508) — Cap clients at 16 with 24h idle timeout; async cert writes.</li>\n<li>Lint &amp; types (#508) — Re-enabled no-unsafe-* rules for src/shared/**; typed protobuf boundary via meshtasticProtobufSchemas.ts; tsconfig.strict.json for incremental shared strictness.</li>\n<li>CI scripts (#508) — GPIO brand check, IPC contract scan scope, log-injection arg detection, document.write XSS check\n…</li>\n</ul>\n"
    },
    {
      "version": "v5.19.2",
      "name": "5.19.2",
      "datetime": "2026-06-05T19:30:03Z",
      "url": "https://github.com/Colorado-Mesh/mesh-client/releases/tag/v5.19.2",
      "prerelease": false,
      "notes": "## Highlights\r\nDual-protocol reliability fixes from a 36-hour audit: MeshCore large contact lists now persist correctly, node names no longer get wiped by sparse updates, Meshtastic MQTT no longer bleeds into MeshCore-only sessions, and hybrid RF+MQTT connection icons apply to your own node too.\r\n\r\n## MeshCore contacts & database\r\n* Large contact sync (#505) — Radios returning 600+ contacts (e.g. 688 over TCP) no longer fail SQLite persist on connect. Batch saves are chunked at the 500-row IPC limit; all slices persist in one transaction.\r\n* Identity preservation — mergeNode skips undefined patch keys; MeshCore upsertNode uses preferNonEmptyTrimmedString so empty or sparse advert data cannot wipe hydrated contact names after restart.\r\n\r\n## Dual-protocol & MQTT\r\n* MeshCore-only users — Live Meshtastic MQTT chat/node ingest is gated on the MeshCore tab unless an RF device is connected. Meshtastic MQTT auto-launch runs only when Meshtastic is the stored protocol.\r\n* Trace-route ingest — Meshtastic MQTT trace-route traffic gated with shouldIngestMeshtasticMqttLive.\r\n* Log noise — Meshtastic MQTT decrypt-failure debug sampling removed for traffic that cannot be decrypted (expected on public brokers without matching PSKs).\r\n\r\n## Meshtastic reliability\r\n* Tapbacks — Optimistic reactions marked sending and re-keyed on RF echo via PacketRouter + SQLite so only one reaction is shown; dedup window widened for client/radio timestamp skew.\r\n* Stub nodes — NodeInfo requested after position/telemetry (not only text) when a node lacks display identity; first telemetry from unknown nodes also triggers NodeInfo.\r\n* Send logging — BLE sendText failures log readable error strings instead of [object Object] in mesh-client.log.\r\n\r\n\r\n## MeshCore Rooms\r\n* Auto-sync — Skips when already logged in; defers quietly when multi-hop route bytes are missing (no hourly warn/debug spam).\r\n* Auth failure recovery — meshcoreRoomAutoLoginFailure cleared when re-enabling auto-login on connect; unified failure handling across connect, scheduler, and loginAllSavedRooms.\r\n\r\n## UI & i18n\r\n* Hybrid self node — Your node in the nodes list and detail modal shows the same RF + purple MQTT path icons as hybrid peers when both transports are up; Source badge shown in node detail.\r\n* Translations — Hybrid RF+MQTT tooltips corrected for de/tr/pl; new check:i18n cross-key rules guard against regressions.\r\n\r\n## Other\r\n* README — Clarifies that the project is for everyone, everywhere, and welcomes participation.\r\n* Dependencies — electron-builder bumped to 26.15.0.\r\n\r\n\r\n**Full Changelog**: https://github.com/Colorado-Mesh/mesh-client/compare/v5.19.1...v5.19.2",
      "notesHtml": "<h2>Highlights</h2>\n<p>Dual-protocol reliability fixes from a 36-hour audit: MeshCore large contact lists now persist correctly, node names no longer get wiped by sparse updates, Meshtastic MQTT no longer bleeds into MeshCore-only sessions, and hybrid RF+MQTT connection icons apply to your own node too.</p>\n<h2>MeshCore contacts &amp; database</h2>\n<ul>\n<li>Large contact sync (#505) — Radios returning 600+ contacts (e.g. 688 over TCP) no longer fail SQLite persist on connect. Batch saves are chunked at the 500-row IPC limit; all slices persist in one transaction.</li>\n<li>Identity preservation — mergeNode skips undefined patch keys; MeshCore upsertNode uses preferNonEmptyTrimmedString so empty or sparse advert data cannot wipe hydrated contact names after restart.</li>\n</ul>\n<h2>Dual-protocol &amp; MQTT</h2>\n<ul>\n<li>MeshCore-only users — Live Meshtastic MQTT chat/node ingest is gated on the MeshCore tab unless an RF device is connected. Meshtastic MQTT auto-launch runs only when Meshtastic is the stored protocol.</li>\n<li>Trace-route ingest — Meshtastic MQTT trace-route traffic gated with shouldIngestMeshtasticMqttLive.</li>\n<li>Log noise — Meshtastic MQTT decrypt-failure debug sampling removed for traffic that cannot be decrypted (expected on public brokers without matching PSKs).</li>\n</ul>\n<h2>Meshtastic reliability</h2>\n<ul>\n<li>Tapbacks — Optimistic reactions marked sending and re-keyed on RF echo via PacketRouter + SQLite so only one reaction is shown; dedup window widened for client/radio timestamp skew.</li>\n<li>Stub nodes — NodeInfo requested after position/telemetry (not only text) when a node lacks display identity; first telemetry from unknown nodes also triggers NodeInfo.</li>\n<li>Send logging — BLE sendText failures log readable error strings instead of [object Object] in mesh-client.log.</li>\n</ul>\n<h2>MeshCore Rooms</h2>\n<ul>\n<li>Auto-sync — Skips when already logged in; defers quietly when multi-hop route bytes are missing (no hourly warn/debug spam).</li>\n<li>Auth failure recovery — meshcoreRoomAutoLoginFailure cleared when re-enabling auto-login on connect; unified failure handling across connect, scheduler, and loginAllSavedRooms.</li>\n</ul>\n<h2>UI &amp; i18n</h2>\n<ul>\n<li>Hybrid self node — Your node in the nodes list and detail modal shows the same RF + purple MQTT path icons as hybrid peers when both transports are up; Source badge shown in node detail.</li>\n<li>Translations — Hybrid RF+MQTT tooltips corrected for de/tr/pl; new check:i18n cross-key rules guard against regressions.</li>\n</ul>\n<h2>Other</h2>\n<ul>\n<li>README — Clarifies that the project is for everyone, everywhere, and welcomes participation.</li>\n<li>Dependencies — electron-builder bumped to 26.15.0.</li>\n</ul>\n<p><strong>Full Changelog</strong>: <a href=\"https://github.com/Colorado-Mesh/mesh-client/compare/v5.19.1...v5.19.2\" target=\"_blank\" rel=\"noopener noreferrer\">https://github.com/Colorado-Mesh/mesh-client/compare/v5.19.1...v5.19.2</a></p>\n"
    },
    {
      "version": "v5.19.1",
      "name": "5.19.1",
      "datetime": "2026-06-04T16:29:46Z",
      "url": "https://github.com/Colorado-Mesh/mesh-client/releases/tag/v5.19.1",
      "prerelease": false,
      "notes": "## Highlights\r\nMeshCore Rooms gets clearer control over saved passwords and smarter behavior after login failures. Meshtastic BLE/serial transport writes are serialized so pings and Store & Forward no longer race the SDK stream. Room background sync is quieter when routes are missing. Database pruning for MeshCore contacts is safer when favorites are involved.\r\n\r\n## MeshCore Rooms\r\n* Saved passwords — Collapsible Saved passwords list in the Rooms sidebar (collapsed by default). Per room: Stop auto-login (keeps password, stops connect-time retries) and Forget saved password (clears credential and turns off auto-login and auto-sync). Same controls on the login overlay and logged-in header.\r\n* Auth failure handling — Wrong password or ACL rejection turns off auto-login and periodic auto-sync but keeps the stored password and shows Auto-login failed until you log in again or change settings manually.\r\n* Connect auto-login — Skips rooms with a recorded auto-login failure until you fix credentials or re-enable Remember password.\r\n* Room sync scheduler — Single-flight ticks, faster route resolve (skipTrace), cooldown updates lastSyncAt on no-route, and route/trace log noise reduced (warn once per room, then debug).\r\n* Troubleshooting — [docs/troubleshooting.md](vscode-file://vscode-app/Applications/Cursor.app/Contents/Resources/app/out/vs/code/electron-sandbox/workbench/docs/troubleshooting.md) documents password rotation and saved-password controls.\r\n\r\n## Meshtastic connection & transport\r\n* Serialized toDevice writes — BLE and serial traffic share one virtual writer queue so concurrent SDK getWriter() calls (ping, Store & Forward, queue) no longer throw WritableStream is locked.\r\n* getMetadata retry — One retry ~8s after configure when NodeDB traffic starves metadata reads on BLE.\r\n\r\n## Database & maintenance\r\n* MeshCore contact count prune — DELETE cap respects non-favorited contacts so favorited nodes cannot leave the DB above maxCount when excess rows are all favorites.\r\n* Merge errors — Invalid merge sources raise MergeSourceInvalidError (MERGE_SOURCE_INVALID) instead of brittle message-string checks.\r\n* Prepared statements — getMeshcoreHopHistory and pruneMeshcorePathHistory use prepareOnce.\r\n* Shared time constants — MS_PER_DAY and related durations live in src/shared/timeConstants.ts so main-process prune cutoffs match renderer helpers.\r\n\r\n## Reliability & tooling\r\n* React hooks lint — react-hooks/refs, set-state-in-effect, and purity are errors; lint runs with --max-warnings 0. Fixes in ModulePanel, RoomsPanel, and useMeshcoreRuntime (hydration race with contact import).\r\n* i18n quality — New check-i18n-quality script (mojibake, meshtastic:// spacing, false friends) in pre-commit checks.\r\n* Dependencies — Lockfile refresh from #503.\r\n\r\n## Bug fixes\r\n* MeshCore auth failure no longer clears UI failure state while still retrying auto-sync ([#503](https://github.com/Colorado-Mesh/mesh-client/pull/503)).\r\n* Room sync log spam when multi-hop routes are unavailable ([#503](https://github.com/Colorado-Mesh/mesh-client/pull/503)).\r\n\r\n**Full Changelog**: https://github.com/Colorado-Mesh/mesh-client/compare/v5.19.0...v5.19.1",
      "notesHtml": "<h2>Highlights</h2>\n<p>MeshCore Rooms gets clearer control over saved passwords and smarter behavior after login failures. Meshtastic BLE/serial transport writes are serialized so pings and Store &amp; Forward no longer race the SDK stream. Room background sync is quieter when routes are missing. Database pruning for MeshCore contacts is safer when favorites are involved.</p>\n<h2>MeshCore Rooms</h2>\n<ul>\n<li>Saved passwords — Collapsible Saved passwords list in the Rooms sidebar (collapsed by default). Per room: Stop auto-login (keeps password, stops connect-time retries) and Forget saved password (clears credential and turns off auto-login and auto-sync). Same controls on the login overlay and logged-in header.</li>\n<li>Auth failure handling — Wrong password or ACL rejection turns off auto-login and periodic auto-sync but keeps the stored password and shows Auto-login failed until you log in again or change settings manually.</li>\n<li>Connect auto-login — Skips rooms with a recorded auto-login failure until you fix credentials or re-enable Remember password.</li>\n<li>Room sync scheduler — Single-flight ticks, faster route resolve (skipTrace), cooldown updates lastSyncAt on no-route, and route/trace log noise reduced (warn once per room, then debug).</li>\n<li>Troubleshooting — <a target=\"_blank\" rel=\"noopener noreferrer\">docs/troubleshooting.md</a> documents password rotation and saved-password controls.</li>\n</ul>\n<h2>Meshtastic connection &amp; transport</h2>\n<ul>\n<li>Serialized toDevice writes — BLE and serial traffic share one virtual writer queue so concurrent SDK getWriter() calls (ping, Store &amp; Forward, queue) no longer throw WritableStream is locked.</li>\n<li>getMetadata retry — One retry ~8s after configure when NodeDB traffic starves metadata reads on BLE.</li>\n</ul>\n<h2>Database &amp; maintenance</h2>\n<ul>\n<li>MeshCore contact count prune — DELETE cap respects non-favorited contacts so favorited nodes cannot leave the DB above maxCount when excess rows are all favorites.</li>\n<li>Merge errors — Invalid merge sources raise MergeSourceInvalidError (MERGE_SOURCE_INVALID) instead of brittle message-string checks.</li>\n<li>Prepared statements — getMeshcoreHopHistory and pruneMeshcorePathHistory use prepareOnce.</li>\n<li>Shared time constants — MS_PER_DAY and related durations live in src/shared/timeConstants.ts so main-process prune cutoffs match renderer helpers.</li>\n</ul>\n<h2>Reliability &amp; tooling</h2>\n<ul>\n<li>React hooks lint — react-hooks/refs, set-state-in-effect, and purity are errors; lint runs with --max-warnings 0. Fixes in ModulePanel, RoomsPanel, and useMeshcoreRuntime (hydration race with contact import).</li>\n<li>i18n quality — New check-i18n-quality script (mojibake, meshtastic:// spacing, false friends) in pre-commit checks.</li>\n<li>Dependencies — Lockfile refresh from #503.</li>\n</ul>\n<h2>Bug fixes</h2>\n<ul>\n<li>MeshCore auth failure no longer clears UI failure state while still retrying auto-sync (<a href=\"https://github.com/Colorado-Mesh/mesh-client/pull/503\" target=\"_blank\" rel=\"noopener noreferrer\">#503</a>).</li>\n<li>Room sync log spam when multi-hop routes are unavailable (<a href=\"https://github.com/Colorado-Mesh/mesh-client/pull/503\" target=\"_blank\" rel=\"noopener noreferrer\">#503</a>).</li>\n</ul>\n<p><strong>Full Changelog</strong>: <a href=\"https://github.com/Colorado-Mesh/mesh-client/compare/v5.19.0...v5.19.1\" target=\"_blank\" rel=\"noopener noreferrer\">https://github.com/Colorado-Mesh/mesh-client/compare/v5.19.0...v5.19.1</a></p>\n"
    },
    {
      "version": "v5.19.0",
      "name": "5.19.0",
      "datetime": "2026-06-04T00:29:22Z",
      "url": "https://github.com/Colorado-Mesh/mesh-client/releases/tag/v5.19.0",
      "prerelease": false,
      "notes": "## Highlights\r\nThis release completes the renderer dual-protocol architecture ([#375](https://github.com/Colorado-Mesh/mesh-client/issues/375), [#377](https://github.com/Colorado-Mesh/mesh-client/issues/377)) — identity-scoped stores, ConnectionDriver, protocol runtimes mounted once from App, and removal of the legacy useDevice / useMeshCore god hooks. MeshCore Rooms lands as a first-class BBS tab with login, posting, admin CLI, and background sync. Meshtastic Radio/Modules panels gain parity with firmware (Display, Bluetooth, Power, Telemetry, Remote Hardware, Administration). Connection reliability improves across sleep/wake, Noble BLE, USB serial, and MQTT. Chat gets a shared composer, stronger dedup, unread badges, and tapback/reply fixes on both protocols.\r\n\r\n## Contributors\r\nSpecial thanks to [Soord](https://github.com/soord) for the heavy lifting on the hook refactor and protocol separation that made the dual-protocol architecture possible, and to [WB3IHY (Joe)](https://github.com/WB3IHY) for Meshtastic Radio/Modules parity work ([#493](https://github.com/Colorado-Mesh/mesh-client/pull/493)).\r\n\r\n## What's Changed\r\n* Architecture & protocol separation ([#475](https://github.com/Colorado-Mesh/mesh-client/pull/475))\r\n* Remove legacy useDevice and useMeshCore; side effects live in useMeshtasticRuntime / useMeshcoreRuntime (mount once from App).\r\n* Identity-scoped Zustand stores (identityStore, nodeStore, messageStore, connectionStore) with SQLite hydration via hydrateIdentityStoresFromDb.\r\n* ConnectionDriver + PacketRouter + Protocol layer (MeshtasticProtocol, MeshCoreProtocol) for driver-first connect and normalized wire events.\r\n* Thin composition hooks: useProtocolFacade, useProtocolConnection, usePanelActions, useConnectionView, useDualProtocolPanelActions.\r\n* Feature gates via ProtocolCapabilities / useRadioProvider instead of hardcoded protocol string checks.\r\n* MeshCore contact batch IPC, startup DB prune single-flight, offline identity slots for pre-connect hydration.\r\n* Docs: docs/renderer-side-effect-migration.md, updated AGENTS.md / ARCHITECTURE.md.\r\n\r\n## Features\r\n* MeshCore Rooms tab — dedicated BBS panel for room-server login, read-only and guest/admin posting, admin CLI/ACL, credentials, auto-sync, and room post ingest ([#483](https://github.com/Colorado-Mesh/mesh-client/pull/483), [#491](https://github.com/Colorado-Mesh/mesh-client/pull/491)).\r\n* Shared ChatComposer — drafts, mentions, chunking, and emoji used by Chat and Rooms ([#491](https://github.com/Colorado-* Mesh/mesh-client/pull/491)).\r\n* Meshtastic Radio/Modules parity ([#493](https://github.com/Colorado-Mesh/mesh-client/pull/493)) — WB3IHY: Display, Bluetooth, and Power fields on Radio panel.\r\n* Telemetry moved to Modules panel; Remote Hardware restored with configurable fields.\r\n* IP Tunnel as status-only section.\r\n* New Administration tab (Device Commands and Danger Zone moved out of Radio).\r\n* All 16 locales updated.\r\n\r\n### MeshCore Rooms — fixes & polish\r\n* Read-only → password upgrade, room routing, and docs parity with pyMC/official app ([#495](https://github.com/Colorado-Mesh/mesh-client/pull/495)).\r\n* Login reliability, dedup, chat noise filtering, and receivedVia merge ([#485](https://github.com/Colorado-Mesh/mesh-client/pull/485), [#486](https://github.com/Colorado-Mesh/mesh-client/pull/486)).\r\n* Read-only room login, SignedPlain posts, and chat badge fixes ([#490](https://github.com/Colorado-Mesh/mesh-client/pull/490)).\r\n* Shorter login timeouts for TCP and 0-hop paths ([#489](https://github.com/Colorado-Mesh/mesh-client/pull/489)).\r\n* Reply previews and tapback echo dedup ([#488](https://github.com/Colorado-Mesh/mesh-client/pull/488)).\r\n* Tray unread for Rooms traffic; room admin relogin ([#492](https://github.com/Colorado-Mesh/mesh-client/pull/492)).\r\n* Rooms scroll layout locked to viewport; jump-to-unread/latest UX matched to Chat ([#499](https://github.com/Colorado-Mesh/mesh-client/pull/499)).\r\n\r\n### Chat & messaging\r\n* Dual-protoco\n…",
      "notesHtml": "<h2>Highlights</h2>\n<p>This release completes the renderer dual-protocol architecture (<a href=\"https://github.com/Colorado-Mesh/mesh-client/issues/375\" target=\"_blank\" rel=\"noopener noreferrer\">#375</a>, <a href=\"https://github.com/Colorado-Mesh/mesh-client/issues/377\" target=\"_blank\" rel=\"noopener noreferrer\">#377</a>) — identity-scoped stores, ConnectionDriver, protocol runtimes mounted once from App, and removal of the legacy useDevice / useMeshCore god hooks. MeshCore Rooms lands as a first-class BBS tab with login, posting, admin CLI, and background sync. Meshtastic Radio/Modules panels gain parity with firmware (Display, Bluetooth, Power, Telemetry, Remote Hardware, Administration). Connection reliability improves across sleep/wake, Noble BLE, USB serial, and MQTT. Chat gets a shared composer, stronger dedup, unread badges, and tapback/reply fixes on both protocols.</p>\n<h2>Contributors</h2>\n<p>Special thanks to <a href=\"https://github.com/soord\" target=\"_blank\" rel=\"noopener noreferrer\">Soord</a> for the heavy lifting on the hook refactor and protocol separation that made the dual-protocol architecture possible, and to <a href=\"https://github.com/WB3IHY\" target=\"_blank\" rel=\"noopener noreferrer\">WB3IHY (Joe)</a> for Meshtastic Radio/Modules parity work (<a href=\"https://github.com/Colorado-Mesh/mesh-client/pull/493\" target=\"_blank\" rel=\"noopener noreferrer\">#493</a>).</p>\n<h2>What's Changed</h2>\n<ul>\n<li>Architecture &amp; protocol separation (<a href=\"https://github.com/Colorado-Mesh/mesh-client/pull/475\" target=\"_blank\" rel=\"noopener noreferrer\">#475</a>)</li>\n<li>Remove legacy useDevice and useMeshCore; side effects live in useMeshtasticRuntime / useMeshcoreRuntime (mount once from App).</li>\n<li>Identity-scoped Zustand stores (identityStore, nodeStore, messageStore, connectionStore) with SQLite hydration via hydrateIdentityStoresFromDb.</li>\n<li>ConnectionDriver + PacketRouter + Protocol layer (MeshtasticProtocol, MeshCoreProtocol) for driver-first connect and normalized wire events.</li>\n<li>Thin composition hooks: useProtocolFacade, useProtocolConnection, usePanelActions, useConnectionView, useDualProtocolPanelActions.</li>\n<li>Feature gates via ProtocolCapabilities / useRadioProvider instead of hardcoded protocol string checks.</li>\n<li>MeshCore contact batch IPC, startup DB prune single-flight, offline identity slots for pre-connect hydration.</li>\n<li>Docs: docs/renderer-side-effect-migration.md, updated AGENTS.md / ARCHITECTURE.md.</li>\n</ul>\n<h2>Features</h2>\n<ul>\n<li>MeshCore Rooms tab — dedicated BBS panel for room-server login, read-only and guest/admin posting, admin CLI/ACL, credentials, auto-sync, and room post ingest (<a href=\"https://github.com/Colorado-Mesh/mesh-client/pull/483\" target=\"_blank\" rel=\"noopener noreferrer\">#483</a>, <a href=\"https://github.com/Colorado-Mesh/mesh-client/pull/491\" target=\"_blank\" rel=\"noopener noreferrer\">#491</a>).</li>\n<li>Shared ChatComposer — drafts, mentions, chunking, and emoji used by Chat and Rooms ([#491](<a href=\"https://github.com/Colorado-\" target=\"_blank\" rel=\"noopener noreferrer\">https://github.com/Colorado-</a>* Mesh/mesh-client/pull/491)).</li>\n<li>Meshtastic Radio/Modules parity (<a href=\"https://github.com/Colorado-Mesh/mesh-client/pull/493\" target=\"_blank\" rel=\"noopener noreferrer\">#493</a>) — WB3IHY: Display, Bluetooth, and Power fields on Radio panel.</li>\n<li>Telemetry moved to Modules panel; Remote Hardware restored with configurable fields.</li>\n<li>IP Tunnel as status-only section.</li>\n<li>New Administration tab (Device Commands and Danger Zone moved out of Radio).</li>\n<li>All 16 locales updated.</li>\n</ul>\n<h3>MeshCore Rooms — fixes &amp; polish</h3>\n<ul>\n<li>Read-only → password upgrade, room routing, and docs parity with pyMC/official app (<a href=\"https://github.com/Colorado-Mesh/mesh-client/pull/495\" target=\"_blank\" rel=\"noopener noreferrer\">#495</a>).</li>\n<li>Login reliability, dedup, chat noise filtering, and receivedVia merge (<a href=\"https://github.com/Colorado-Mesh/mesh-client/pull/485\" target=\"_blank\" rel=\"noopener noreferrer\">#485</a>, <a href=\"https://github.com/Colorado-Mesh/mesh-client/pull/486\" target=\"_blank\" rel=\"noopener noreferrer\">#486</a>).</li>\n<li>Read-only room login, SignedPlain posts, and chat badge fixes (<a href=\"https://github.com/Colorado-Mesh/mesh-client/pull/490\" target=\"_blank\" rel=\"noopener noreferrer\">#490</a>).</li>\n<li>Shorter login timeouts for TCP and 0-hop paths (<a href=\"https://github.com/Colorado-Mesh/mesh-client/pull/489\" target=\"_blank\" rel=\"noopener noreferrer\">#489</a>).</li>\n<li>Reply previews and tapback echo dedup (<a href=\"https://github.com/Colorado-Mesh/mesh-client/pull/488\" target=\"_blank\" rel=\"noopener noreferrer\">#488</a>).</li>\n<li>Tray unread for Rooms traffic; room admin relogin (<a href=\"https://github.com/Colorado-Mesh/mesh-client/pull/492\" target=\"_blank\" rel=\"noopener noreferrer\">#492</a>).</li>\n<li>Rooms scroll layout locked to viewport; jump-to-unread/latest UX matched to Chat (<a href=\"https://github.com/Colorado-Mesh/mesh-client/pull/499\" target=\"_blank\" rel=\"noopener noreferrer\">#499</a>).</li>\n</ul>\n<h3>Chat &amp; messaging</h3>\n<ul>\n<li>Dual-protoco\n…</li>\n</ul>\n"
    },
    {
      "version": "v5.18.0",
      "name": "5.18.0",
      "datetime": "2026-05-26T03:01:50Z",
      "url": "https://github.com/Colorado-Mesh/mesh-client/releases/tag/v5.18.0",
      "prerelease": false,
      "notes": "## Highlights\r\nPKC-based Meshtastic remote admin and private MQTT brokers (multi-PSK, correct AES-CTR, MQTT-only identity) are the headline reliability work in this release, with a long tail of fixes across Linux Web Bluetooth, Store & Forward chat history, and an experimental Flathub-ready Flatpak pipeline. Chat gains a chunked composer with a durable outbox; the map and connection UI pick up channel URLs, backlog controls, and clearer disconnect feedback.\r\n\r\n## What's Changed\r\n### Features\r\nChunked message composer, durable outbox, MeshCore MQTT-only queue guard, and chat fixes (#421)\r\nExpose all theme colors in color scheme section (#423)\r\nExperimental Flathub-ready Flatpak build support (#434)\r\nPulse header red on error disconnect; MeshCore MQTT reconnect fix (#446)\r\nMap UX, channel URLs, backlog, and node ID formatting (#447)\r\nPKC remote admin, private MQTT brokers, and Meshtastic reliability (#453)\r\n\r\n### Bug fixes\r\nHarden main process, tighten IPC types, and bump deps (#424)\r\nLinux Web Bluetooth first-message ACK, stale watchdog, and auto-reconnect (#429)\r\nHoist readable-stream for Linux asar MQTT packaging (#430)\r\nReplace single 100ms BLE safety read with multi-shot probes for LoRa latency (#431)\r\nSubscribe to fromNum GATT notify for unsolicited mesh traffic on Linux BLE (#432)\r\n3-second background fromRadio poll between write cycles (#433)\r\nFlatpak: node-generator arch flag, aarch64 builder, Flathub remote, CI runners, Electron bundle paths, offline archives, vmwgfx GPU policy (#437–#445)\r\nUSB C++17 Linux rebuild and Store & Forward chat decode (#448)\r\nMeshCore/Meshtastic stability, S&F history, and static GPS sync (#449)\r\nMeshtastic last_heard freshness and garbled TEXT_MESSAGE handling (#451)\r\nSerialize remote admin fetch and PKI packets (#454)\r\nMultiple MQTT channel PSKs in connection panel (#455)\r\nMQTT channel PSK/index, uplink encrypt, remote admin over BLE (#456)\r\nMQTT PSK parsing, MQTT-only identity, remote admin snapshot (#457–#458)\r\nMeshtastic MQTT, PKC remote admin, and tapback reactions (#459)\r\nRemote admin stability, MQTT decrypt keys, i18n quality (#460)\r\nCorrect AES-CTR nonce for MQTT encrypt/decrypt (#461)\r\nRemote admin reliability, MQTT outbound identity, i18n (#462)\r\nRemote admin PKI fallback, MQTT from guard, snapshot hardening (#463)\r\nRemote admin response correlation and channel read hardening (#465)\r\nPrioritize publish-time MQTT PSKs for broker echo decrypt (#466)\r\n## Other\r\nREADME: chunked outbox, MeshCore TCP port (#422)\r\nDocs sync with Flatpak and recent features (#450, #464)\r\nFlatpak workflow hardening and Node.js 24 (#435, #436)\r\nDependabot: pin idna and pymdown-extensions (#425)\r\n\r\n## New Contributors\r\n@WB3IHY made their first contribution in https://github.com/Colorado-Mesh/mesh-client/pull/461\r\n\r\n**Full Changelog**: https://github.com/Colorado-Mesh/mesh-client/compare/v5.17.0...v5.18.0",
      "notesHtml": "<h2>Highlights</h2>\n<p>PKC-based Meshtastic remote admin and private MQTT brokers (multi-PSK, correct AES-CTR, MQTT-only identity) are the headline reliability work in this release, with a long tail of fixes across Linux Web Bluetooth, Store &amp; Forward chat history, and an experimental Flathub-ready Flatpak pipeline. Chat gains a chunked composer with a durable outbox; the map and connection UI pick up channel URLs, backlog controls, and clearer disconnect feedback.</p>\n<h2>What's Changed</h2>\n<h3>Features</h3>\n<p>Chunked message composer, durable outbox, MeshCore MQTT-only queue guard, and chat fixes (#421)\nExpose all theme colors in color scheme section (#423)\nExperimental Flathub-ready Flatpak build support (#434)\nPulse header red on error disconnect; MeshCore MQTT reconnect fix (#446)\nMap UX, channel URLs, backlog, and node ID formatting (#447)\nPKC remote admin, private MQTT brokers, and Meshtastic reliability (#453)</p>\n<h3>Bug fixes</h3>\n<p>Harden main process, tighten IPC types, and bump deps (#424)\nLinux Web Bluetooth first-message ACK, stale watchdog, and auto-reconnect (#429)\nHoist readable-stream for Linux asar MQTT packaging (#430)\nReplace single 100ms BLE safety read with multi-shot probes for LoRa latency (#431)\nSubscribe to fromNum GATT notify for unsolicited mesh traffic on Linux BLE (#432)\n3-second background fromRadio poll between write cycles (#433)\nFlatpak: node-generator arch flag, aarch64 builder, Flathub remote, CI runners, Electron bundle paths, offline archives, vmwgfx GPU policy (#437–#445)\nUSB C++17 Linux rebuild and Store &amp; Forward chat decode (#448)\nMeshCore/Meshtastic stability, S&amp;F history, and static GPS sync (#449)\nMeshtastic last_heard freshness and garbled TEXT_MESSAGE handling (#451)\nSerialize remote admin fetch and PKI packets (#454)\nMultiple MQTT channel PSKs in connection panel (#455)\nMQTT channel PSK/index, uplink encrypt, remote admin over BLE (#456)\nMQTT PSK parsing, MQTT-only identity, remote admin snapshot (#457–#458)\nMeshtastic MQTT, PKC remote admin, and tapback reactions (#459)\nRemote admin stability, MQTT decrypt keys, i18n quality (#460)\nCorrect AES-CTR nonce for MQTT encrypt/decrypt (#461)\nRemote admin reliability, MQTT outbound identity, i18n (#462)\nRemote admin PKI fallback, MQTT from guard, snapshot hardening (#463)\nRemote admin response correlation and channel read hardening (#465)\nPrioritize publish-time MQTT PSKs for broker echo decrypt (#466)</p>\n<h2>Other</h2>\n<p>README: chunked outbox, MeshCore TCP port (#422)\nDocs sync with Flatpak and recent features (#450, #464)\nFlatpak workflow hardening and Node.js 24 (#435, #436)\nDependabot: pin idna and pymdown-extensions (#425)</p>\n<h2>New Contributors</h2>\n<p>@WB3IHY made their first contribution in <a href=\"https://github.com/Colorado-Mesh/mesh-client/pull/461\" target=\"_blank\" rel=\"noopener noreferrer\">https://github.com/Colorado-Mesh/mesh-client/pull/461</a></p>\n<p><strong>Full Changelog</strong>: <a href=\"https://github.com/Colorado-Mesh/mesh-client/compare/v5.17.0...v5.18.0\" target=\"_blank\" rel=\"noopener noreferrer\">https://github.com/Colorado-Mesh/mesh-client/compare/v5.17.0...v5.18.0</a></p>\n"
    },
    {
      "version": "v5.17.0",
      "name": "5.17.0",
      "datetime": "2026-05-18T01:07:37Z",
      "url": "https://github.com/Colorado-Mesh/mesh-client/releases/tag/v5.17.0",
      "prerelease": false,
      "notes": "Features\r\n   - Flexible MeshCore Connections: Added support for specifying a custom TCP port (defaulting to 5000) when connecting to MeshCore devices.\r\n   - Enhanced Diagnostics:\r\n     - Improved \"Foreign LoRa\" detection by surfacing nearby MeshCore traffic within the Meshtastic diagnostics panel.\r\n     - Added support for recording MeshCore RF traffic overheard by Meshtastic listeners, including proximity filtering and sender resolution.\r\n     - Added \"MeshCore heard on Meshtastic frequency\" section to the diagnostics panel.\r\n\r\n  Bug Fixes\r\n   - Clipboard Support: Rewrote chat message copying to use main-process IPC, resolving silent failures in the Electron environment on macOS.\r\n   - UI/UX Improvements:\r\n     - Fixed a behavior where the \"unread divider\" would persist even when messages fit on the screen without scrolling.\r\n     - Replaced relative height calculations with explicit pixel values in PacketDistributionPanel to fix rendering issues.\r\n   - Diagnostics Accuracy:\r\n     - Hop diagnostics are now skipped for MQTT-only nodes to prevent false \"impossible hop\" alerts caused by hops_away=0 reporting.\r\n     - Hardened \"Foreign LoRa\" promotion and TCP address parsing, including better handling of bare IPv6 addresses.\r\n   - I18n (Internationalization):\r\n     - Conducted a major repair of over 300 translations across 15 locales that were corrupted by automated auditing tools.\r\n     - Restored technical terms like \"Flood Advert,\" \"TAK,\" \"MGRS,\" and \"Router\" to their correct forms.\r\n     - Added validation guards to the i18n scripts to prevent technical protocol terms from being translated in the future.\r\n\r\n  Refactoring & Maintenance\r\n   - Keyboard Shortcuts Removal: Removed the global keyboard shortcut system (Cmd/Ctrl+1-9, search toggles, etc.) to reduce maintenance overhead and simplify the codebase.\r\n   - Code Quality:\r\n     - Extracted TCP address parsing into a shared utility with comprehensive test coverage.\r\n     - Cleaned up unused components including KeyboardShortcutsModal and SearchModal.\r\n     - Fixed various formatting issues and hardened type guards across the communication hooks.\r\n   - Dependencies: Updated project dependencies to their latest versions.\r\n\r\n\r\n**Full Changelog**: https://github.com/Colorado-Mesh/mesh-client/compare/v5.16.0...v5.17.0",
      "notesHtml": "<p>Features</p>\n<ul>\n<li>Flexible MeshCore Connections: Added support for specifying a custom TCP port (defaulting to 5000) when connecting to MeshCore devices.</li>\n<li>Enhanced Diagnostics:<ul>\n<li>Improved \"Foreign LoRa\" detection by surfacing nearby MeshCore traffic within the Meshtastic diagnostics panel.</li>\n<li>Added support for recording MeshCore RF traffic overheard by Meshtastic listeners, including proximity filtering and sender resolution.</li>\n<li>Added \"MeshCore heard on Meshtastic frequency\" section to the diagnostics panel.</li>\n</ul>\n</li>\n</ul>\n<p>  Bug Fixes</p>\n<ul>\n<li>Clipboard Support: Rewrote chat message copying to use main-process IPC, resolving silent failures in the Electron environment on macOS.</li>\n<li>UI/UX Improvements:<ul>\n<li>Fixed a behavior where the \"unread divider\" would persist even when messages fit on the screen without scrolling.</li>\n<li>Replaced relative height calculations with explicit pixel values in PacketDistributionPanel to fix rendering issues.</li>\n</ul>\n</li>\n<li>Diagnostics Accuracy:<ul>\n<li>Hop diagnostics are now skipped for MQTT-only nodes to prevent false \"impossible hop\" alerts caused by hops_away=0 reporting.</li>\n<li>Hardened \"Foreign LoRa\" promotion and TCP address parsing, including better handling of bare IPv6 addresses.</li>\n</ul>\n</li>\n<li>I18n (Internationalization):<ul>\n<li>Conducted a major repair of over 300 translations across 15 locales that were corrupted by automated auditing tools.</li>\n<li>Restored technical terms like \"Flood Advert,\" \"TAK,\" \"MGRS,\" and \"Router\" to their correct forms.</li>\n<li>Added validation guards to the i18n scripts to prevent technical protocol terms from being translated in the future.</li>\n</ul>\n</li>\n</ul>\n<p>  Refactoring &amp; Maintenance</p>\n<ul>\n<li>Keyboard Shortcuts Removal: Removed the global keyboard shortcut system (Cmd/Ctrl+1-9, search toggles, etc.) to reduce maintenance overhead and simplify the codebase.</li>\n<li>Code Quality:<ul>\n<li>Extracted TCP address parsing into a shared utility with comprehensive test coverage.</li>\n<li>Cleaned up unused components including KeyboardShortcutsModal and SearchModal.</li>\n<li>Fixed various formatting issues and hardened type guards across the communication hooks.</li>\n</ul>\n</li>\n<li>Dependencies: Updated project dependencies to their latest versions.</li>\n</ul>\n<p><strong>Full Changelog</strong>: <a href=\"https://github.com/Colorado-Mesh/mesh-client/compare/v5.16.0...v5.17.0\" target=\"_blank\" rel=\"noopener noreferrer\">https://github.com/Colorado-Mesh/mesh-client/compare/v5.16.0...v5.17.0</a></p>\n"
    },
    {
      "version": "v5.16.0",
      "name": "5.16.0",
      "datetime": "2026-05-16T20:23:55Z",
      "url": "https://github.com/Colorado-Mesh/mesh-client/releases/tag/v5.16.0",
      "prerelease": false,
      "notes": "🌟 New Features\r\n\r\n  Chat & Messaging Suite\r\n   - Message Starring: Bookmark important messages with a star icon; view all bookmarks in the new Starred Messages view (accessible via the toolbar star icon).\r\n   - Link Previews: Chat messages now automatically generate rich previews (title, description, image) for URLs using Open Graph metadata.\r\n   - Per-Conversation Mute: Silence specific channels or DMs independently using the new bell toggle in the chat toolbar.\r\n   - Advanced Chat Tools:\r\n     - Draft Persistence: Unsent messages are now automatically saved per conversation and restored when you return.\r\n     - Message Export: Export chat history to formatted .txt files via the new export tool.\r\n     - @mention Autocomplete: Type @ to trigger a node-name autocomplete dropdown with keyboard navigation.\r\n     - Jump to Date: Quickly navigate long chat histories using the new calendar date picker.\r\n     - Sender Filtering: Click any sender's name to filter the current conversation to only their messages.\r\n   - DM Info Header: View real-time battery, SNR, and last-heard status directly above Direct Message conversations.\r\n   - Copy Message: Added a dedicated \"Copy\" button to message hover actions for quick clipboard access.\r\n\r\n  Node Management & Monitoring\r\n   - Node Notes: Save private, persistent notes for any node directly within the Node Detail modal.\r\n   - Watch & Notify: \"Watch\" specific nodes to receive OS-level notifications whenever they change status (Online/Offline).\r\n   - Node Health Score: A new 0–100 health metric—analyzing signal quality, recency, load, and battery—is now displayed in the node list.\r\n   - JSON Export: Added a button to export the entire node list to a JSON file.\r\n\r\n  Visualization & Diagnostics\r\n   - RF Histograms (Cmd/Ctrl + R): New panel visualizing SNR, RSSI, and hop-count distributions across the mesh.\r\n   - Peer Graph (Cmd/Ctrl + G): Interactive force-directed SVG graph showing connectivity between nodes.\r\n   - CU History Chart: A 24-hour timeline chart for Channel Utilization now appears in the Diagnostics panel.\r\n   - CU Leaderboard: A new leaderboard in the Stats tab ranks nodes by their reported channel utilization.\r\n\r\n  MeshCore Enhancements\r\n   - Path Diagnostics: Improved detection of path instability and \"weak links\" using per-hop SNR trace data.\r\n   - RF Signal Analysis: Added automated detection for elevated noise floors and excessive flooding conditions.\r\n\r\n  ---\r\n\r\n  🛠 Improvements & Bug Fixes\r\n\r\n   - Message Deduplication: Enhanced cross-transport (RF/MQTT) deduping logic with a 10-minute window to prevent duplicate bubbles for the same content.\r\n   - Notification Hardening:\r\n     - Fixed a bug where the dock badge was missing when the window was hidden while the chat tab was active.\r\n     - Refined sound notification logic to ensure alerts fire correctly when the app is minimized or focused on other tabs.\r\n   - Security:\r\n     - Strengthened Content Security Policy (CSP) and Link Preview fetcher (SSRF protection).\r\n     - Improved JWT hygiene for LetsMesh providers.\r\n   - UI/UX:\r\n     - Added dedicated sidebar icons for Graph and RF panels.\r\n     - Fixed duplicate emojis in node action buttons.\r\n     - Corrected MeshCore last_heard conversion from seconds to milliseconds.\r\n     - Fixed erroneous notification sounds triggered during panel remounts.\r\n   - Localization: Updated translations across all 15 supported languages, including fixes for \"hop\" terminology and placeholder artifacts.\r\n\r\n  ---\r\n\r\n  🏗 Under the Hood\r\n\r\n   - Performance: Optimized the Peer Graph to use connected-node filtering, preventing O(n²) performance issues on large meshes.\r\n   - Tooling: Enforced node/pnpm engine versions via pnpm engine-strict in package.json.\r\n   - Testing: Extensive new test coverage (500+ lines of tests) for link previews, message deduping, notification stores, and diagnostic engines.\r\n\r\n**Full Changelog**: https://github.com/Colorado-Mesh/mesh-client/compare/v5.15.1...v5.16.0",
      "notesHtml": "<p>🌟 New Features</p>\n<p>  Chat &amp; Messaging Suite</p>\n<ul>\n<li>Message Starring: Bookmark important messages with a star icon; view all bookmarks in the new Starred Messages view (accessible via the toolbar star icon).</li>\n<li>Link Previews: Chat messages now automatically generate rich previews (title, description, image) for URLs using Open Graph metadata.</li>\n<li>Per-Conversation Mute: Silence specific channels or DMs independently using the new bell toggle in the chat toolbar.</li>\n<li>Advanced Chat Tools:<ul>\n<li>Draft Persistence: Unsent messages are now automatically saved per conversation and restored when you return.</li>\n<li>Message Export: Export chat history to formatted .txt files via the new export tool.</li>\n<li>@mention Autocomplete: Type @ to trigger a node-name autocomplete dropdown with keyboard navigation.</li>\n<li>Jump to Date: Quickly navigate long chat histories using the new calendar date picker.</li>\n<li>Sender Filtering: Click any sender's name to filter the current conversation to only their messages.</li>\n</ul>\n</li>\n<li>DM Info Header: View real-time battery, SNR, and last-heard status directly above Direct Message conversations.</li>\n<li>Copy Message: Added a dedicated \"Copy\" button to message hover actions for quick clipboard access.</li>\n</ul>\n<p>  Node Management &amp; Monitoring</p>\n<ul>\n<li>Node Notes: Save private, persistent notes for any node directly within the Node Detail modal.</li>\n<li>Watch &amp; Notify: \"Watch\" specific nodes to receive OS-level notifications whenever they change status (Online/Offline).</li>\n<li>Node Health Score: A new 0–100 health metric—analyzing signal quality, recency, load, and battery—is now displayed in the node list.</li>\n<li>JSON Export: Added a button to export the entire node list to a JSON file.</li>\n</ul>\n<p>  Visualization &amp; Diagnostics</p>\n<ul>\n<li>RF Histograms (Cmd/Ctrl + R): New panel visualizing SNR, RSSI, and hop-count distributions across the mesh.</li>\n<li>Peer Graph (Cmd/Ctrl + G): Interactive force-directed SVG graph showing connectivity between nodes.</li>\n<li>CU History Chart: A 24-hour timeline chart for Channel Utilization now appears in the Diagnostics panel.</li>\n<li>CU Leaderboard: A new leaderboard in the Stats tab ranks nodes by their reported channel utilization.</li>\n</ul>\n<p>  MeshCore Enhancements</p>\n<ul>\n<li>Path Diagnostics: Improved detection of path instability and \"weak links\" using per-hop SNR trace data.</li>\n<li>RF Signal Analysis: Added automated detection for elevated noise floors and excessive flooding conditions.</li>\n</ul>\n<hr />\n<p>  🛠 Improvements &amp; Bug Fixes</p>\n<ul>\n<li>Message Deduplication: Enhanced cross-transport (RF/MQTT) deduping logic with a 10-minute window to prevent duplicate bubbles for the same content.</li>\n<li>Notification Hardening:<ul>\n<li>Fixed a bug where the dock badge was missing when the window was hidden while the chat tab was active.</li>\n<li>Refined sound notification logic to ensure alerts fire correctly when the app is minimized or focused on other tabs.</li>\n</ul>\n</li>\n<li>Security:<ul>\n<li>Strengthened Content Security Policy (CSP) and Link Preview fetcher (SSRF protection).</li>\n<li>Improved JWT hygiene for LetsMesh providers.</li>\n</ul>\n</li>\n<li>UI/UX:<ul>\n<li>Added dedicated sidebar icons for Graph and RF panels.</li>\n<li>Fixed duplicate emojis in node action buttons.</li>\n<li>Corrected MeshCore last_heard conversion from seconds to milliseconds.</li>\n<li>Fixed erroneous notification sounds triggered during panel remounts.</li>\n</ul>\n</li>\n<li>Localization: Updated translations across all 15 supported languages, including fixes for \"hop\" terminology and placeholder artifacts.</li>\n</ul>\n<hr />\n<p>  🏗 Under the Hood</p>\n<ul>\n<li>Performance: Optimized the Peer Graph to use connected-node filtering, preventing O(n²) performance issues on large meshes.</li>\n<li>Tooling: Enforced node/pnpm engine versions via pnpm engine-strict in package.json.</li>\n<li>Testing: Extensive new test coverage (500+ lines of tests) for link previews, message deduping, notification stores, and diagnostic engines.</li>\n</ul>\n<p><strong>Full Changelog</strong>: <a href=\"https://github.com/Colorado-Mesh/mesh-client/compare/v5.15.1...v5.16.0\" target=\"_blank\" rel=\"noopener noreferrer\">https://github.com/Colorado-Mesh/mesh-client/compare/v5.15.1...v5.16.0</a></p>\n"
    },
    {
      "version": "v5.15.1",
      "name": "5.15.1",
      "datetime": "2026-05-10T19:24:57Z",
      "url": "https://github.com/Colorado-Mesh/mesh-client/releases/tag/v5.15.1",
      "prerelease": false,
      "notes": "Highlights\r\n   - Improved MQTT reconnection reliability with a new exponential backoff schedule and increased retry budget.\r\n   - Hardened Windows builds and resolved a Windows 11-specific crash in the native About panel by implementing an HTML fallback.\r\n   - Added OS notifications for manual update checks and unified the update status UI across the application.\r\n\r\n   Bug Fixes\r\n   - Harden Windows builds and MQTT reconnects (#408)\r\n   - Guard native Electron calls to prevent crashes and improved crash reporting diagnosis.\r\n   - Deduplicate @meshtastic/core to fix Meshtastic USB serial transport issues (Fixes #407).\r\n   - Implement capped exponential backoff for MQTT (60s base, 45m cap) with jitter.\r\n   - Fix native About panel and Help links for Windows 11 compatibility (Fixes #406).\r\n\r\n  Other Changes\r\n   - Enforce Windows runner for Windows builds in CI.\r\n   - Bump dependencies\r\n\r\n\r\n**Full Changelog**: https://github.com/Colorado-Mesh/mesh-client/compare/v5.15.0...v5.15.1",
      "notesHtml": "<p>Highlights</p>\n<ul>\n<li>Improved MQTT reconnection reliability with a new exponential backoff schedule and increased retry budget.</li>\n<li>Hardened Windows builds and resolved a Windows 11-specific crash in the native About panel by implementing an HTML fallback.</li>\n<li>Added OS notifications for manual update checks and unified the update status UI across the application.</li>\n</ul>\n<p>   Bug Fixes</p>\n<ul>\n<li>Harden Windows builds and MQTT reconnects (#408)</li>\n<li>Guard native Electron calls to prevent crashes and improved crash reporting diagnosis.</li>\n<li>Deduplicate @meshtastic/core to fix Meshtastic USB serial transport issues (Fixes #407).</li>\n<li>Implement capped exponential backoff for MQTT (60s base, 45m cap) with jitter.</li>\n<li>Fix native About panel and Help links for Windows 11 compatibility (Fixes #406).</li>\n</ul>\n<p>  Other Changes</p>\n<ul>\n<li>Enforce Windows runner for Windows builds in CI.</li>\n<li>Bump dependencies</li>\n</ul>\n<p><strong>Full Changelog</strong>: <a href=\"https://github.com/Colorado-Mesh/mesh-client/compare/v5.15.0...v5.15.1\" target=\"_blank\" rel=\"noopener noreferrer\">https://github.com/Colorado-Mesh/mesh-client/compare/v5.15.0...v5.15.1</a></p>\n"
    }
  ],
  "changelogSource": "github",
  "changelogUpdatedAt": "2026-07-21T02:52:02.859Z"
}
