Commit Graph

1688 Commits

Author SHA1 Message Date
James Smith 2ec5085673 fix: align pyproject meshcore pin with requirements.txt (>=2.3.0)
Caught by test_dependency_files_integrity, which had been buried in the
never-reached tail of the test suite.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-12 09:30:19 +01:00
James Smith 379b6a9667 docs: record UI direction — dashboards for map-heavy modes
Phase 5 decision gate of the architecture refactor plan: dedicated
dashboard pages are the pattern for map-centric modes; APRS and
Meshtastic migrations to follow under separate plans.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-12 08:46:37 +01:00
James Smith 5cff7de117 refactor: single dependency probe in capability detection; real test coverage
detect_mode_availability accepts a pre-computed dep_status so the agent
probes once; interface and fallback paths now have content-level tests.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-12 08:37:30 +01:00
James Smith 0588055d1f refactor: extract shared capability detection from agent
utils/capabilities.py now owns interface detection and mode
availability; the agent delegates via detect_interfaces() and
detect_mode_availability(). The agent keeps config gating and
tool_details population to preserve its result shape exactly.

The moved fallback path uses utils.dependencies.check_tool instead of
the agent's old shutil.which fallback; check_tool also searches
Homebrew paths, a strict superset (strictly better detection).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-12 08:31:54 +01:00
James Smith e14271c5ee test: mode registry consistency checks; fail fast if registry missing
Also documents the registry-driven mode integration in CLAUDE.md.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-12 08:11:04 +01:00
James Smith e38b8fb464 refactor: registry-driven mode init dispatch in switchMode
A failing mode init now logs instead of aborting the remainder of
switchMode (deliberate hardening; previously an exception skipped
title/visuals updates).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-12 08:03:40 +01:00
James Smith a1b1e5a77e refactor: derive sidebar toggles and destroy map from registry
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 21:46:40 +01:00
James Smith 5d3811cc60 refactor: derive modeCatalog and modesWithVisuals from registry
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 21:29:37 +01:00
James Smith 8813d069bc feat: introduce frontend mode registry (no behaviour change)
window.INTERCEPT_MODES mirrors the existing modeCatalog, sidebar
toggles, visuals list, destroy map, and switchMode init branches.
Derivations follow in subsequent commits; a temporary console guard
verifies registry/catalog parity at runtime.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 21:16:40 +01:00
James Smith cdb5285b68 fix: reject non-canonical subpaths in agent proxy allowlist
requests/urllib3 collapse dot segments before sending, so traversal
like wifi/v2/../../x escaped the prefix allowlist. Only canonical
paths are now forwarded; regression tests included.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 17:49:19 +01:00
James Smith 67847eb708 refactor: route agent wifi clients through generic proxy
Removes the one-off proxy_wifi_clients route and the dead getApiBase()
helper; the allowlisted passthrough now covers agent wifi traffic.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 17:43:16 +01:00
James Smith c870f118bf feat: allowlisted generic agent proxy route
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 17:41:01 +01:00
James Smith a202c9dd94 refactor: agent satellite predictor reads TLEs from unified store
Removes the agent's own CelesTrak download (the source of the stray
gp.php artifact) — the store is now the single TLE source for app and
agent alike.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 17:31:00 +01:00
James Smith 07887b7c99 test: isolate the TLE store suite-wide
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 17:29:03 +01:00
James Smith 0af3028151 fix: point doppler and ground-station scheduler at unified TLE store
Both silently fell back to static bundled TLEs after the removal of
routes.satellite._tle_cache.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 17:25:29 +01:00
James Smith 5e996654fe refactor: weather sat prediction reads TLEs from unified store
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 17:23:20 +01:00
James Smith 320fe82348 refactor: hoist TLE reads and batch write-backs in satellite request paths
_resolve_satellite_request now operates on a caller-provided dict and
accumulates write-backs, flushed once per request behind a guard —
avoids per-satellite full-dict copies and store-cache thrash, and a
transient DB error can no longer fail a read request.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 17:20:01 +01:00
James Smith 1c72e15c7c refactor: satellite routes read/write TLEs via unified store
data/satellites.py is no longer rewritten at runtime; it remains as
the read-only seed for the store.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 17:12:23 +01:00
James Smith 74d5663f73 fix: harden TLE store for cross-process use
- busy_timeout so concurrent app+agent writers wait instead of raising
- seed from _connect() so update-before-first-read can't drop the seed
- regression tests: seed ordering, concurrent writer, default DB path

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 17:07:30 +01:00
James Smith f4a9cb7da6 feat: add unified SQLite-backed TLE store
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 16:58:09 +01:00
James Smith 2f6afd5e28 test: use shared fake_process fixture in agent mode tests
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 16:50:20 +01:00
James Smith 9463d53763 test: address review feedback on fake_process fixture
- document str defaults / bytes for binary-mode callers
- wire __exit__ to False so exceptions are not suppressed
- exercise exited-process path through subprocess.run

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 16:48:13 +01:00
James Smith c177dd354a test: add shared fake_process fixture for complete Popen mocking
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 16:44:04 +01:00
James Smith d4652017f5 fix: stabilize test suite and repair frontend/backend wiring
- meshcore pin >=2.3.0 (EventType.STATS_CORE floor); setup.sh derives
  optional packages from requirements.txt; Python 3.10 warning
- agent-mode wifi clients proxy route + bare-array response handling
- remove dead AIS/ACARS/VDL2 SPA wiring and orphaned partials/CSS
- agent TLE download to data/tle/ (was littering repo root as gp.php)
- gate deferred background init off under pytest (mock-pollution race)
- complete Popen mocks (context manager protocol, communicate tuples)
- real pipe fds in weather-sat decoder tests (fd 10/11 collision caused
  10s SQLite stalls); satellite tests no longer rewrite data/satellites.py
- register 'live' pytest marker, excluded by default
- update stale test assertions to current APIs

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 16:42:33 +01:00
James Smith b68a53eb53 fix: prevent full page reload when clicking Main Dashboard button
Intercept .nav-dashboard-btn clicks to perform SPA-style navigation
instead of a full page reload. After switchMode() updates the URL to
/?mode=<x> via pushState, clicking href="/" previously caused a round-
trip reload. Now the click handler stops active scans, destroys the
current mode, shows the welcome overlay, and pushes '/' onto history.

Also update popstate to restore the welcome page when navigating back
to '/' with no mode param.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-21 22:07:41 +01:00
James Smith d68d1ec53a fix(adsb): update Planespotters User-Agent to include contact URL
Planespotters.net now requires a descriptive User-Agent with a contact
URL or email — generic strings return 403. Updated to comply with their
API policy.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-21 21:34:42 +01:00
James Smith 9c15ece508 fix: hide signalViewWrap entirely in modesWithVisuals to prevent layout bleed
The flex container was still occupying space even when all its children
were hidden, causing a blank box to overlap mode-specific content in
Bluetooth, WiFi, SSTV and other modesWithVisuals.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-21 21:21:13 +01:00
James Smith fe222c0393 fix: don't restore #output visibility in non-sensor modes
SensorDashboard.applyViewState was resetting output.style.display=''
in the else branch, undoing switchMode's modesWithVisuals hide for
waterfall, morse, ook, and every other mode with its own visuals.
Only touch #output when mode === 'sensor'.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-21 21:12:09 +01:00
James Smith 68cafe8cd0 fix: move applyViewState calls after output display override in switchMode
switchMode() forces output.style.display='block' for modes not in
modesWithVisuals (line ~4906). Our applyViewState calls were placed
before this line, so the override undid the dashboard hide. Moving
them after ensures SensorDashboard can correctly hide #output in
dashboard mode.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-21 17:47:42 +01:00
James Smith d01742678c chore: update satellite TLE data
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-21 15:49:53 +01:00
James Smith 31ae70b8fa feat: wire PagerDirectory and SensorDashboard into pager and sensor modes
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-21 14:25:13 +01:00
James Smith e7f13a5856 fix: escape channel, snr, and reading values in sensor dashboard cards 2026-05-21 13:01:46 +01:00
James Smith a9ed367148 feat: add SensorDashboard JS component 2026-05-21 13:00:09 +01:00
James Smith 2505218385 fix: use CSS variables for accent-green-rgb and accent-purple-rgb in sensor dashboard 2026-05-21 12:58:31 +01:00
James Smith b5c35890af feat: add sensor dashboard view CSS 2026-05-21 12:56:45 +01:00
James Smith 484d9ce21b fix: refresh directory timestamps on applyViewState 2026-05-21 12:55:49 +01:00
James Smith 9353527e1b feat: add PagerDirectory JS component 2026-05-21 12:51:41 +01:00
James Smith fd3ad63971 fix: add display flex to pdir-panel, use accent-purple-rgb variable
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-21 12:49:54 +01:00
James Smith 2e583649d0 feat: add pager directory view CSS 2026-05-21 12:46:31 +01:00
James Smith a3c509aa94 feat: add HTML scaffolding for pager directory and sensor dashboard views
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-21 12:39:57 +01:00
James Smith f26a820b1d docs: add pager/sensor display revamp implementation plan
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-21 12:27:10 +01:00
James Smith 901e7f95e8 docs: add pager/sensor display revamp design spec
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-21 12:17:04 +01:00
James Smith 592d11aae2 feat: add graticule toggle control to all Leaflet maps
Adds a bottomleft grid button (MapUtils.addGraticuleControl) to every
map in the app — Meshtastic, MeshCore, Drone, SSTV/ISS, BT Locate,
WebSDR, and Weather Satellite — defaulting to visible. The weather
satellite map's bespoke addStyledGridOverlay() is removed in favour of
the shared implementation. Also updates map-utils.css with button
styles and map-utils.js with the new addGraticuleControl() method.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-21 11:09:39 +01:00
James Smith 30a0085f1d ci: split test suite into two parallel jobs to prevent OOM
GitHub Actions ubuntu-latest has 7GB RAM. Running all 1362 tests in
a single process exhausts it (~9 min, runner shutdown signal). Split
into two matrix jobs (test_[a-l] and test_[m-z]) so each job starts
with fresh memory, halving peak usage.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-21 08:25:20 +01:00
James Smith b30d883974 fix: resolve CI test failures and OOM kill in satellite tests
- pyproject.toml: sync missing deps (flask-wtf, flask-compress,
  simple-websocket, gunicorn, gevent, psutil, cryptography, meshcore,
  pre-commit) so test_requirements integrity check passes
- tests/conftest.py: set INTERCEPT_DISABLE_AUTH=1 so auth routes
  return 200 instead of 302 in tests
- routes/bluetooth_v2.py: add device_to_dict() helper that flattens
  heuristics to top level for test_bluetooth_api serialization tests
- utils/bluetooth/heuristics.py: evaluate() now returns the device so
  callers can chain; was returning None
- tests/test_satellite.py: reduce hours 48→2 in pass-prediction test
  to prevent OOM kill on GitHub Actions 7GB runner at the 59% mark

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-20 22:34:02 +01:00
James Smith ea8f72f7ff chore: bump version to 2.27.0
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
v2.27.0
2026-05-20 22:08:42 +01:00
James Smith a3f2fa7b88 fix: resolve two-window hang and sweep UI/theming updates
Fix app becoming unresponsive when two browser windows are open: the
root cause was HTTP/1.1 connection pool exhaustion (6-connection limit
per origin). VoiceAlerts was opening 3 SSE streams per window by
default, so two windows produced 8 connections and permanently starved
all regular HTTP requests.

- voice-alerts.js: default all streams to false (opt-in) to stay within
  the browser connection limit; existing user preferences in localStorage
  are preserved
- routes/alerts.py: replace direct AlertManager.stream_events() with
  sse_stream_fanout so both windows receive every alert instead of
  competing for the same queue
- routes/bluetooth_v2.py: same fanout fix via subscribe_fanout_queue,
  preserving named SSE events (device_update, scan_started, etc.)

Also includes accumulated UI/theming changes: accent-cyan CSS variable
sweep across mode CSS/JS files, standalone dashboard pages, template
updates, satellite TLE data refresh, and tile provider default rename.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-20 22:01:10 +01:00
James Smith 5100f55586 fix: introduce --accent-cyan-rgb to make all opacity variants theme-aware
All files used hardcoded rgba(74, 163/158, 255, X) values in actual CSS
rules that CSS variable overrides couldn't touch. Solution: add
--accent-cyan-rgb triplet to variables.css root/light/enhanced blocks,
then replace every rgba(74,1xx,255,) occurrence across all CSS files
with rgba(var(--accent-cyan-rgb),). Enhanced tier sets the triplet to
200, 150, 40 (amber), so tscm.css panel bg, index.css card borders,
and all other tinted surfaces go amber automatically.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-20 08:53:25 +01:00
James Smith 9d41ffbb59 fix: apply UI tier to standalone dashboard pages (ADS-B, AIS, Satellite)
Each dashboard is a separate HTML page that doesn't inherit the main SPA's
localStorage restore. Add a synchronous tier-restore script before CSS loads
so html[data-ui-tier] selectors fire on first paint.

Also add enhanced/lean tier override blocks to each dashboard CSS to remap
the dashboard-local variables (--bg-dark, --bg-panel, --radar-cyan, etc.)
that variables.css doesn't cover, and add lean-mode scanline/bg hide rules
since components.css is not loaded on these pages.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-20 08:44:29 +01:00
James Smith 517eb8cb77 revert: restore brand logo to fixed blue (#00d4ff) — brand identity not UI chrome
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-20 08:41:11 +01:00