Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ Mesh-Client supports **three mesh stacks** in one desktop app. Use the header **

- **Tri-protocol switcher**: Meshtastic, MeshCore, and Reticulum run simultaneously; per-protocol unread badges (green / cyan / amber); passive toast notifications when an inactive protocol receives traffic
- **Localization**: 16 languages via static JSON bundles; fully offline — see [Localization & Languages](docs/localization.md)
- **Accessibility**: modal focus trap, screen reader labels, reduce-motion toggle — see [Accessibility Checklist](docs/accessibility-checklist.md)
- **Accessibility**: modal focus trap, screen reader labels, reduce-motion and **Use 24-hour time** toggles in App → Appearance — see [Accessibility Checklist](docs/accessibility-checklist.md)
- **Log panel**: live stream, **Analyze** heuristics, export/delete; Reticulum sidecar lines tagged `[ReticulumSidecar]`
- **SQLite persistence**: protocol-scoped history and settings; DB export/import/clear in the App tab; **Export for GitHub** (zip: debug snapshot + logs) and **Export for Developer** (includes full SQLite — share privately only)
- **Updates & tray**: footer update status; system tray unread badge when the window is backgrounded
Expand Down Expand Up @@ -202,7 +202,7 @@ These sections apply to the two LoRa companion-radio stacks. Reticulum uses the
**Node Management**

- Node list with SNR, battery, GPS, **last heard** (any live RF packet—position, telemetry, traceroute, text—not only chat); **signal bars** appear only for direct (0-hop) RF neighbors; multi-hop and MQTT-only paths omit bars; SNR in traces and neighbor views uses **color-coded quality** (good / marginal / poor)
- **Cross-Protocol Signal Analyzer**: foreign LoRa traffic detection (MeshCore, Reticulum RNS, other Meshtastic, unknown) on the **Meshtastic** Diagnostics tab and in node detail when RF rows are present; not shown on MeshCore/Reticulum tabs
- **Cross-Protocol Signal Analyzer**: foreign LoRa traffic detection (MeshCore, Reticulum RNS, other Meshtastic, unknown) on the **Meshtastic** and **MeshCore** Diagnostics tabs and in node detail when RF rows are present; not shown on the Reticulum Diagnostics tab
- Distance filter, favorite/pin nodes, device role icons
- Node Detail Modal: DM, trace route with per-hop display, delete node, neighbor info, **Map Report** (Meshtastic), PaxCounter, Detection Sensor, **channel utilization** (Meshtastic), **export/share contact** (MeshCore), **node notes** (free-text, SQLite-persisted), **watch / notify** (OS desktop notification on online/offline transition)
- **Node Health Score**: composite 0–100 badge on each node row (signal 40 pts, recency 30 pts, load 20 pts, battery 10 pts); color-coded green / yellow / red with tooltip breakdown
Expand Down
8 changes: 7 additions & 1 deletion docs/contributing.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,13 @@ contributor guide lives in the repository at

## Quality Checks

Run these before opening a PR:
Prefer **`pnpm run check:pr`** before opening a PR (lint + typecheck + `typecheck:strict-shared` + full `test:run`, plus path-aware sidecar checks when relevant):

```bash
pnpm run check:pr
```

Or run pieces individually:

```bash
pnpm run test:run
Expand Down
2 changes: 1 addition & 1 deletion docs/development-environment.md
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ curl -s http://127.0.0.1:19437/api/v1/status
# → {"status":"ok",...}
```

In Electron dev: open the **Reticulum** protocol pill (amber) → **Connection** → **Start stack**. Then use **Radio** to generate/import identity and manage interfaces (add, edit, delete). Dev builds resolve the binary from `reticulum-sidecar/target/debug/mesh-client-reticulum`.
In Electron dev: open the **Reticulum** protocol pill (amber) → **Connection** → **Start stack**. Then use **Network** for identity (generate/import) and **Connection** for interfaces (add, edit, delete). Dev builds resolve the binary from `reticulum-sidecar/target/debug/mesh-client-reticulum`.

#### Keep Rust and the sidecar current

Expand Down
2 changes: 1 addition & 1 deletion docs/diagnostics.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ This document is the authoritative reference for every diagnostic output in Mesh
- **NodeListPanel**: inline anomaly badges, redundancy `+N` echo count, MQTT-only node dimming, Node Health Score badge, JSON export
- **MapPanel**: channel utilization halos, routing anomaly aura circles
- **RF Histograms panel**: SNR, RSSI, and hop-count bar charts across all nodes
- **Peer Graph panel**: SVG force-directed graph of directly connected nodes (hops 0–1)
- **Peer Graph panel**: SVG force-directed graph of directly connected nodes (hops 0–1) — **Meshtastic and MeshCore only**; Reticulum uses the **Topology** tab instead

All three protocols share one **Diagnostics** sidebar tab; sections differ by `ProtocolCapabilities` (see **Multi-protocol tab scoping** below).

Expand Down
2 changes: 1 addition & 1 deletion docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ Also useful:
- Noble BLE coexistence when a Reticulum BLE RNode is connected — [Troubleshooting](troubleshooting.md#reticulum-ble-rnode-blocks-meshtasticmeshcore-noble-ble)
- Sidecar build / start failures — [Troubleshooting](troubleshooting.md#reticulum-sidecar-wont-start-or-health-poll-times-out)
- **Support**
- [Diagnostics](diagnostics.md) — LoRa routing/RF (Meshtastic & MeshCore), foreign LoRa overhear (Meshtastic tab), Reticulum interface audit; protocol-scoped row filtering
- [Diagnostics](diagnostics.md) — LoRa routing/RF (Meshtastic & MeshCore), foreign LoRa overhear (Meshtastic & MeshCore tabs), Reticulum interface audit; protocol-scoped row filtering
- [Key backup and cryptography](key-backup-and-crypto.md) (per-node full key pair backup; MT → MC migration)
- [Troubleshooting](troubleshooting.md)
- Export for GitHub / stuck Chat — [Troubleshooting](troubleshooting.md#reporting-bugs-export-for-github-app-tab)
Expand Down
3 changes: 2 additions & 1 deletion docs/reticulum-sidecar-ipc.md
Original file line number Diff line number Diff line change
Expand Up @@ -236,13 +236,14 @@ Event types: `lxmf_message`, `lxmf_outbound_status`, `events_lagged` (WS subscri

## Electron bridge

Renderer calls `electronAPI.reticulum.*`; main process proxies to this API (sandboxed renderer cannot reach localhost directly).
Renderer calls `electronAPI.reticulum.*`; main process proxies to this API (sandboxed renderer cannot reach localhost directly). Lifecycle / proxy / Remote / factory-reset handlers live in `src/main/ipc/reticulum-handlers.ts`. Reticulum destination / Remote address / inbound-policy DB handlers are in `src/main/ipc/reticulum-db-handlers.ts`; RRC room history uses `src/main/ipc/rrc-db-handlers.ts`.

| IPC channel | Role |
| ------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------ |
| `reticulum:start` / `stop` / `getStatus` | Sidecar lifecycle |
| `reticulum:syncInterfaceIssueScope` | Drop TCP/TX latch entries for disabled/removed interfaces; sticky enabled-name filter for later log lines |
| `reticulum:proxyGet` / `proxyPost` / `proxyPut` / `proxyDelete` | HTTP proxy to paths above |
| `reticulum:factoryReset` | Factory reset (generic `proxyPost` blocks `/api/v1/system/factory-reset`; UI must use this channel) |
| `reticulum:validateConfig` | One-shot `validate-config --json` against `userData/reticulum/config` (read-only; safe while stack runs) |
| `reticulum:readDefaultConfigFile` | Read first existing system rnsd config path |
| `reticulum:showConfigImportDialog` | Native file picker for config import |
Expand Down
21 changes: 20 additions & 1 deletion docs/troubleshooting.md
Original file line number Diff line number Diff line change
Expand Up @@ -445,6 +445,17 @@ flatpak run org.coloradomesh.MeshClient

**Fix**: Click **Forget this device** on the reconnect card and pair fresh using the Bluetooth picker.

### Dual-radio Noble BLE startup serialization (macOS/Windows)

When both Meshtastic and MeshCore have **different** saved BLE peripherals, startup auto-connect is serialized so two Noble connects do not race:

- Coordinator: `meshcoreDualNobleBleInit.ts`; wired from **`App.tsx` `useLayoutEffect`** (not `useEffect` — child ConnectionPanel auto-connect effects must see primary/secondary roles first).
- **Primary** is chosen from `mesh-client:protocol` localStorage (`meshcore` / `meshtastic`; Reticulum or missing → Meshtastic).
- **Secondary** waits on `awaitNobleBlePrimaryAutoConnectSettled()` (GATT + handshake ready or first attempt settled) — not full device configure.
- All Noble IPC connects go through `withNobleBleConnectMutex()`.

See also wake recovery under [Sleep, wake, and long-running sessions](#sleep-wake-and-long-running-sessions) (Meshtastic-first stagger). For Reticulum BLE RNode vs Noble, see [Reticulum BLE RNode blocks Meshtastic/MeshCore Noble BLE](#reticulum-ble-rnode-blocks-meshtasticmeshcore-noble-ble).

## USB serial

### Serial port not detected
Expand Down Expand Up @@ -568,6 +579,8 @@ After sleep or hibernate, mesh-client uses the same resume path as macOS: reconn

**Linux Web Bluetooth:** Manual reconnect from the connection banner still requires a user gesture (Connect / picker). Linux does not use Noble IPC; see **Linux-specific** under [BLE known issues](#ble-known-issues) above for pairing and adapter reset steps.

**Reticulum (all platforms):** On suspend, `onPowerSuspend` clears in-memory rnsh sessions and rncp transfers. On resume, `onPowerResume` restarts the sidecar via `connect()` unless the user disconnected.

### Long-running sessions (multi-day uptime)

If mesh-client stays open for **days** on a busy mesh (especially **MeshCore BLE-only** with hundreds of repeaters):
Expand Down Expand Up @@ -700,6 +713,10 @@ If a module section stays on **Waiting for … settings from the device** with A
- Confirm **Channel PSKs** on the Connection tab match the channel (16- or 32-byte base64 per line; `ChannelName=base64` for MQTT-only names).
- Enable **Enable TLS (mqtts / wss)** when the broker requires TLS on a non-standard port.

### Meshtastic SDK routing failures mark chat rows failed

When the Meshtastic SDK logs a routing / queue failure, mesh-client intercepts matched `console.error` / `console.warn` lines via `meshtasticSdkRoutingErrorConsoleHook.ts`, logs them at `console.debug`, and applies `applyMeshtasticOutboundRoutingErrorFromLog` (or `FromRejection`) so the outbound Chat row shows **Failed**. Unmatched queue rejections may still appear as `[meshtasticSdkRoutingErrorLog]`.

## MeshCore

### MeshCore contact age prune and favorites
Expand Down Expand Up @@ -1028,7 +1045,7 @@ Unrecognized codes pass through unchanged.

### Reticulum `proxyGet` fetch failed / many `[ReticulumIPC] start` lines

**Symptoms**: Device log or devtools shows `Error occurred in handler for 'reticulum:proxyGet': TypeError: fetch failed`, often in bursts of three or more at once. The app log may also show dozens of `[ReticulumIPC] start` entries within a few seconds while Nomad/Radio/Peers panels stay empty or stale.
**Symptoms**: Device log or devtools shows `Error occurred in handler for 'reticulum:proxyGet': TypeError: fetch failed`, often in bursts of three or more at once. The app log may also show dozens of `[ReticulumIPC] start` entries within a few seconds while Nomad/Network/Peers panels stay empty or stale.

**Cause**: Overlapping sidecar start attempts restart the process before its HTTP server is ready (start/reconnect storm). Panels keep calling `proxyGet` against a dead or stale localhost port during the churn.

Expand Down Expand Up @@ -1305,6 +1322,8 @@ See [reticulum.md — RNode over Wi-Fi](reticulum.md#rnode-over-wi-fi).

**Request enable / 422**: `sendRncpRequestEnable` must POST LXMF with a `text` field (not `content`) — wrong key → HTTP **422**. After you send request-enable, the peer's `mesh-client:rncp-receive-dest:v1:<hash>` reply is applied only if a pending mark exists (`rncpReceiveDestSharePending`, TTL); shares without a prior request-enable from this session are ignored.

**Sleep / wake**: Suspend clears in-memory rnsh sessions and rncp transfers; reopen Remote (or wait for resume reconnect) after wake. See [Sleep, wake, and long-running sessions](#sleep-wake-and-long-running-sessions).

### Reticulum Remote inbound rncp blocked (Ask mode / policy)

**Symptoms**: Incoming file offers never arrive, or an offer is auto-declined; a peer reports their send was rejected.
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@
"@types/react-dom": "^19.2.3",
"@typescript-eslint/eslint-plugin": "^8.65.0",
"@typescript-eslint/parser": "^8.65.0",
"@vitejs/plugin-react": "^6.0.4",
"@vitejs/plugin-react": "^6.0.5",
"@vitest/coverage-v8": "^4.1.10",
"concurrently": "^9.2.4",
"electron": "^41.10.3",
Expand Down Expand Up @@ -218,7 +218,7 @@
"tailwindcss": "^4.3.3",
"typescript": "^6.0.3",
"typescript-eslint": "^8.65.0",
"vite": "^8.1.5",
"vite": "^8.2.0",
"vitest": "^4.1.10",
"vitest-axe": "1.0.0-pre.5",
"zustand": "^5.0.14"
Expand Down
Loading