Rename Mesh Chat to Meshtastic Chat, embed the Infonet terminal with Arti/Tor warmup, improve the agent shell PTY (git in the backend image, operator PATH), and add docker-compose.override for local image builds. Gitignore Hermes Agent runtime installs.
Co-authored-by: Cursor <cursoragent@cursor.com>
Add Telegram OSINT with hourly incremental t.me scraping, metro geocoding
separate from news centroids, threat-intercept popup UI with inline media,
and HTML markers above alert boxes so pins stay clickable. Expose GFW_API_TOKEN
in onboarding and Settings Maritime; harden GFW/CCTV/geo fetchers. Port Osiris-
derived recon, SCM, entity graph, malware/cyber feeds, sanctions, and submarine
cable layers with tests and documentation.
Co-authored-by: Cursor <cursoragent@cursor.com>
On 2026-05-23, stream.aisstream.io went fully offline (TCP timeouts on port
443). The backend kept respawning the node WebSocket proxy every few
seconds with nothing arriving. From the operator's POV the ships layer
silently went empty — no banner, no log surfacing, no way to tell whether
it was their config / network / viewport filter / upstream.
Backend:
* ais_proxy_status() now also returns:
- connected (bool): true when a vessel message arrived in last 60s
- last_msg_age_seconds (int | None)
- proxy_spawn_count (int): proxy respawns — sustained growth without
connected means upstream is dead
* /api/health escalates top status to "degraded" when AIS_API_KEY is set
but the proxy is currently disconnected. Existing degraded_tls signal
preserved.
Frontend:
* useAisUpstreamHealth hook polls /api/health every 30s, derives the
outage state. Defensively only reports outage once spawn_count > 0 so
operators who haven't opted in don't see the banner.
* AisUpstreamBanner component renders a dismissible amber notice
"Ship data temporarily unavailable — AISStream upstream is offline"
mounted on the main app shell.
7 backend tests pin the status-shape contract and the /api/health
escalation behavior in both with-key and without-key configurations.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Reported by @tg12. Pre-fix, the Settings panel stored real third-party
Copernicus CDSE client_id + client_secret in browser localStorage /
sessionStorage via the privacy storage helper, and the proxy routes
required those values to come back in every tile/token request body.
Any same-origin script (XSS, malicious browser extension, dev-tools
HAR export) had read access to the credentials.
This change moves them server-side, behind the same .env-backed admin
flow every other third-party API key (OpenSky, AIS Stream, Finnhub,
Shodan, …) already uses.
Backend
-------
backend/services/api_settings.py
* Added SENTINEL_CLIENT_ID and SENTINEL_CLIENT_SECRET entries to
API_REGISTRY. The existing GET/PUT /api/settings/api-keys flow
(already require_local_operator-gated, .env-backed) now manages
them — no new route surface.
backend/routers/tools.py
* /api/sentinel/token and /api/sentinel/tile resolve credentials via
a new _resolve_sentinel_credentials() helper: body fields win for
back-compat with any legacy callers, otherwise the helper reads
SENTINEL_CLIENT_ID / SENTINEL_CLIENT_SECRET from os.environ.
* When neither source has a value, the route returns 400 with a
friendly pointer ("Set SENTINEL_CLIENT_ID and SENTINEL_CLIENT_SECRET
in the API Keys panel") instead of the curt "required" message.
The user's standing rule against hostile errors applies.
* Function bodies only — decorator lines untouched, so this PR does
not conflict with #303 (which adds Depends(require_local_operator)
to the same routes).
Frontend
--------
frontend/src/lib/sentinelHub.ts — rewritten
* Removed: getSentinelCredentials / setSentinelCredentials /
clearSentinelCredentials / getSentinelCredentialStorageMode.
These were the browser-storage read/write helpers; their existence
was the bug.
* Added: checkBackendSentinelStatus(), refreshSentinelStatus(),
getCachedSentinelStatus(), and a kept-for-back-compat
hasSentinelCredentials() shim. Status is sourced from
/api/settings/api-keys (the same endpoint the API Keys panel
already uses), so we don't add a new route just for this read.
* Added: migrateLegacySentinelBrowserKeys() — one-shot, idempotent
helper that clears sb_sentinel_client_id / _secret / _instance_id
from BOTH localStorage and sessionStorage. We deliberately do NOT
auto-POST those legacy browser values to the backend; doing so
would silently migrate a secret across a trust boundary without
operator consent. Operators re-enter once in the API Keys panel
and the legacy keys get wiped here.
* fetchSentinelTile and getSentinelToken no longer send client_id /
client_secret in the request body. The backend uses .env.
frontend/src/components/SettingsPanel.tsx
* Dropped sb_sentinel_client_id / _secret / _instance_id from
PRIVACY_SENSITIVE_BROWSER_KEYS — they're no longer written.
* SentinelTab rewritten: removed the inline Client ID / Client Secret
inputs + Save / Clear / Test buttons. Replaced with a status panel
that calls checkBackendSentinelStatus() on mount, a one-click
"Open API Keys Panel" button, and a migration banner that appears
only when migrateLegacySentinelBrowserKeys() actually cleared
something.
* Setup guide STEP 3 now points to the API Keys panel instead of
the local form.
frontend/src/app/page.tsx
* Added a one-time useEffect that fires checkBackendSentinelStatus()
on mount so the cached value (which the synchronous
hasSentinelCredentials() shim reads) is populated before
MaplibreViewer's tile-URL memo runs.
Tests
-----
backend/tests/test_sentinel_credentials_server_side.py (new)
* API_REGISTRY surface — sentinel_client_id / sentinel_client_secret
are registered with the right env_keys, ALLOWED_ENV_KEYS lets
/api/settings/api-keys PUT them.
* Resolution order — body wins, env is fallback, neither → 400 with
the friendly pointer message, and NO upstream HTTP call when
neither source has credentials (asserted via
MagicMock(side_effect=AssertionError)).
* /api/sentinel/tile same shape.
frontend/src/__tests__/utils/sentinelHub.test.ts (new)
* migrateLegacySentinelBrowserKeys clears localStorage AND
sessionStorage, reports what it cleared, idempotent.
* fetchSentinelTile + getSentinelToken POST WITHOUT client_id /
client_secret in the body (plants leaked credentials in browser
storage first to prove they are NOT picked up).
* checkBackendSentinelStatus parses /api/settings/api-keys correctly:
true only when both keys is_set, false on partial config or
network errors.
All 7 backend tests + 8 frontend tests pass locally. The
test_no_new_duplicate_routes guard and the api-settings test suite
still pass.
Credit: @tg12 for the audit report.
Introduce a lightweight i18n system with auto-detection of browser
language and localStorage persistence. Add complete Chinese translations
for all major UI sections: navigation, controls, update dialogs, node
activation, terminal launcher, data layers, settings, filters, and more.
Technical terms (Wormhole, Infonet, Mesh, Shodan, SAR, etc.) are
intentionally kept in English. Falls back to English when Chinese
translation is not found.
Co-authored-by: wangsudong <wangsudong@kylinos.cn>
- Add FINNHUB_API_KEY to docker-compose.yml so financial ticker works
in Docker deployments
- Update default layer config: planes/ships ON, satellites only for
space, no fire hotspots, military bases + internet outages for infra,
all SIGINT except HF digital spots
- Add MapLibre native clustering to APRS markers (matches Meshtastic)
with cluster radius 42, breaks apart at zoom 8
Gate messages now propagate via the Infonet hashchain as encrypted blobs — every node syncs them
through normal chain sync while only Gate members with MLS keys can decrypt. Added mesh reputation
system, peer push workers, voluntary Wormhole opt-in for node participation, fork recovery,
killwormhole scripts, obfuscated terminology, and hardened the self-updater to protect encryption
keys and chain state during updates.
New features: Shodan search, train tracking, Sentinel Hub imagery, 8 new intelligence layers,
CCTV expansion to 11,000+ cameras across 6 countries, Mesh Terminal CLI, prediction markets,
desktop-shell scaffold, and comprehensive mesh test suite (215 frontend + backend tests passing).
Community contributors: @wa1id, @AlborzNazari, @adust09, @Xpirix, @imqdcr, @csysp, @suranyami,
@chr0n1x, @johan-martensson, @singularfailure, @smithbh, @OrfeoTerkuci, @deuza, @tm-const,
@Elhard1, @ttulttul
Map ~35,000 power generation facilities from 164 countries using the
WRI Global Power Plant Database (CC BY 4.0). Follows the existing
datacenter layer pattern with clustered icon symbols, amber color
scheme, and click popups showing fuel type, capacity, and operator.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add 18 US military bases (Japan, Guam, South Korea, Hawaii, Diego Garcia)
as a toggleable map layer. Follows the existing data center layer pattern:
static JSON → backend fetcher → slow-tier API → frontend GeoJSON layer.
Includes red circle markers with labels, click popups showing operator
and branch info, and a toggle in the left panel.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Remove WorldviewRightPanel from left HUD (declutter)
- Restore sliding sidebar animation via motion.div on both HUD containers
- Left tab (LAYERS): springs to x:-360 when hidden, tab tracks edge
- Right tab (INTEL): springs to x:+360 when hidden, tab tracks edge
- Both use spring animation (damping:30 stiffness:250)
- ChevronLeft/Right icons flip direction with open state
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Former-commit-id: 5a573165d27db1704f513ce9fd503ddc3f6892ef
Removes WorldviewRightPanel render and import from page.tsx.
The effects state is preserved as it continues to feed MaplibreViewer.
Left HUD column now contains only the data layers panel.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Former-commit-id: 0cdb2a60bd8436b7226866e2f4086496beed1587
New features:
- POTUS fleet (AF1, AF2, Marine One) with hot-pink icons + gold halo ring
- 9-color aircraft system: military, medical, police, VIP, privacy, dictators
- Sentinel-2 fullscreen overlay with download/copy/open buttons (green themed)
- Carrier homeport deconfliction — distinct pier positions instead of stacking
- Toggle all data layers button (cyan when active, excludes MODIS Terra)
- Version badge + update checker + Discussions shortcut in UI
- Overhauled MapLegend with POTUS fleet, wildfires, infrastructure sections
- Data center map layer with ~700 global DCs from curated dataset
Fixes:
- All Air Force Two ICAO hex codes now correctly identified
- POTUS icon priority over grounded state
- Sentinel-2 no longer overlaps bottom coordinate bar
- Region dossier Nominatim 429 rate-limit retry/backoff
- Docker ENV legacy format warnings resolved
- UI buttons cyan in dark mode, grey in light mode
- Circuit breaker for flaky upstream APIs
Community: @suranyami — parallel multi-arch Docker builds + runtime BACKEND_URL fix (PR #35, #44)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Former-commit-id: 7c523df70a2d26f675603166e3513d29230592cd
Previously, NEXT_PUBLIC_API_URL was a build-time Next.js variable, making
it impossible to configure the backend URL in docker-compose `environment`
without rebuilding the image.
This change introduces a proper server-side proxy:
- next.config.ts: adds a rewrite rule that forwards all /api/* requests
to BACKEND_URL (read at server startup, not baked at build time).
Defaults to http://localhost:8000 so local dev works without config.
- api.ts: API_BASE is now an empty string — all fetch calls use relative
/api/... paths, which the Next.js server proxies to the backend.
- docker-compose.yml: replaces NEXT_PUBLIC_API_URL build arg with a
runtime BACKEND_URL env var defaulting to http://backend:8000, using
Docker's internal networking. Port 8000 no longer needs to be exposed.
- README: updates Docker setup docs, standalone compose example, and
environment variable reference to reflect BACKEND_URL.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Former-commit-id: b4c9e78cdd
New features:
- Custom RSS Feed Manager: add/remove/prioritize up to 20 news sources
from the Settings panel with weight levels 1-5. Persists across restarts.
- Global Data Center Map Layer: 2,000+ DCs plotted worldwide with clustering,
server-rack icons, and automatic internet outage cross-referencing.
- Imperative map rendering: high-volume layers bypass React reconciliation
via direct setData() calls with debounced updates on dense layers.
- Enhanced /api/health with per-source freshness timestamps and counts.
Fixes:
- Data center coordinates fixed for 187 Southern Hemisphere entries
- Docker CORS_ORIGINS passthrough in docker-compose.yml
- Start scripts warn on Python 3.13+ compatibility
- Settings panel redesigned with tabbed UI (API Keys / News Feeds)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Former-commit-id: 950c308f04
New intelligence layers:
- NASA FIRMS VIIRS fire hotspots (5K+ global thermal anomalies, flame icons)
- NOAA space weather badge (Kp index in status bar)
- IODA regional internet outage monitoring (grey markers, BGP/ping only)
Key improvements:
- Fire clusters use flame-shaped icons (not circles) for clear differentiation
- Internet outages are region-level with reliable datasources only
- Removed radiation layer (no viable free real-time API)
- All outage markers grey to avoid color confusion with other layers
- Filtered out merit-nt telescope data that produced misleading percentages
Updated changelog modal, README, and package.json for v0.5.0.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Former-commit-id: 195c6b64b9
Add 4 new intelligence layers for v0.5:
- NASA FIRMS VIIRS thermal anomaly tiles (frontend-only WMTS)
- NOAA Space Weather Kp index badge in bottom bar
- Safecast radiation monitoring with clustered markers
- IODA internet outage alerts at country centroids
All use free keyless APIs. All layers default to off.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Former-commit-id: 7cb926e227
New features:
- NASA GIBS (MODIS Terra) daily satellite imagery with 30-day time slider
- Esri World Imagery high-res satellite layer (sub-meter, zoom 18+)
- KiwiSDR SDR receivers on map with embedded radio tuner
- Sentinel-2 intel card — right-click for recent satellite photo popup
- LOCATE bar — search by coordinates or place name (Nominatim geocoding)
- SATELLITE style preset in bottom bar cycling
- v0.4 changelog modal on first launch
Fixes:
- Satellite imagery renders below data icons (imagery-ceiling anchor)
- Sentinel-2 opens full-res PNG directly (not STAC catalog JSON)
- Light/dark theme: UI stays dark, only map basemap changes
Security:
- Removed test files with hardcoded API keys from tracking
- Removed .git_backup directory from tracking
- Updated .gitignore to exclude test files, dev scripts, cache files
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Former-commit-id: e89e992293