Commit Graph
188 Commits
Author SHA1 Message Date
German KhokhlovandClaude Opus 5.5 35bfe203a6 Merge remote-tracking branch 'origin/main' into german/street-level-slim
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-08 16:04:02 +04:00
German KhokhlovandClaude Opus 5.5 1db3290e0b chore(street-level): format; drop nearest.js from tool configs
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-08 15:07:32 +04:00
Sameh Khamis 1594db9497 Merge main into feat/voice-core and reconcile layer capabilities 2026-10-07 13:14:31 -07:00
German KhokhlovandClaude Opus 5.5 b5a78826f8 refactor(street-level): slim Mapillary tile proxy — memory cache only, no server holds
Drop the disk tile cache (.gev-cache/mapillary/tiles, background sweep,
size cap, legacy retrim), the server-side 401/403/429 holds, the upstream
concurrency semaphore and per-waiter abort bookkeeping. The client already
pauses on 429 and stops on a rejected key.

Keep: server-side token, {configured}-only status, strict coverage path
validation (z11-14), image-layer trimming, same-site gate and per-IP limit,
HTTPS redirect pinning to the tile origin, the streamed size cap, the error
mapping the client reads, a 24 h byte-budget LRU memory cache, in-flight
coalescing via the shared coalesceProxyRequest, and browser Cache-Control.

Routes and constants fold into mapillary.js and mapillary/tiles.js.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-07 22:27:34 +04:00
German KhokhlovandClaude Opus 5.5 37a96072fa refactor(street-level): one provider, no orbit overview, no prewarm, simpler tile choice
The layer now owns its Mapillary parts directly: the provider registry,
pick router, multi-provider UI summary, params codec helper and provider
context are gone. createStreetLevelLayer({ source }) builds coverage,
sequences, the nearest-image lookup and the MapillaryJS viewer itself; a
single providerOn switch keeps the share link's `mapillary` option (off
draws nothing), and getParams/setParams keep { mapillary, pano, sinceDays }.

No z0-5 overview points: above 60 km nothing is drawn and the panel says to
zoom in; the proxy now serves only coverage z11-14. Tiles come from the
visible ground within range of the camera, ranked from the ground under it
(no line-of-sight ranking or near-range padding). MapillaryJS loads on the
first photo; viewer prewarm is removed. Key status, a rejected key and a
rate limit share one `blocked` state on coverage.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-07 22:19:24 +04:00
German KhokhlovandClaude Opus 5.5 0f41fb04cd refactor(street-level): drop FOLLOW and Google 3D ground casting
FOLLOW is gone: no setFollow, follow state, map-stack availability or
handoff listener. Opening a photo still frames it with one flight through
the application's deferred navigation (begin/reassert), so a slow photo
never overrides newer navigation and tracking is released as before.

Ground casting is gone: groundCast.js, meshSampler.js, the surface mode,
the draped-to-cast swap and remesh. Coverage lines are always draped
GroundPolylinePrimitives (ClassificationType.BOTH); cones and the marker
clamp to the ground and keep the horizon cull. The terrain/meshFloor/ground
services and meshFloor.visibleTilesetLoaded are no longer needed.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-07 21:59:15 +04:00
German KhokhlovandClaude Opus 5.5 fbbc4cda5c refactor(ui): remove floating, resizable rail panels
PR #768 bundled a portable-panel windowing system with the Street Level
layer. Remove it so CCTV and Street Level are ordinary docked right-rail
panels again, as on main before the merge.

Removed:
- header drag to float, 8-way edge/corner resize, double-press snap-back,
  dockOnCollapse, command-dock clearance, float hint toast, floating z floor,
  persisted floating geometry and ResizeObserver re-clamping
  (panelPositionControls.js restored to its pre-#768 version)
- src/ui/panelResize.js and its tests, panelDock.test.mjs
- onPanelResized/dockPanel wiring in PanelChrome, the application shell and
  StreetLevelControls (EXPAND/SHRINK no longer docks)
- :not(.panel-floating) guards and .panel-floating/.panel-portable/resize CSS
- qa:panel-resize, qa-panel-resize.mjs, qa-panelDrag.mjs, their tests, the
  CI "Portable panel gate" step, QA_FAIL_ON_RETRY, and the Street Level
  gate's float/resize/dock steps
- floating-panel docs in README, CHANGELOG, CURRENT-STATE, KNOWN-ISSUES

Kept: the Street Level panel as a docked rail panel (share/cockpit/rail
lists, layout controller, rail and Cyber CSS, EXPAND viewer), and the
independent right-rail alignment fix (settledLeftRailTop, 9dde7b4).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-07 21:39:33 +04:00
Said TurkseverandClaude Opus 5.5 1fa129ea8e fix(street-level): camera ownership, mesh refresh, panel CSP (Sameh's review)
- Photo framing and FOLLOW claim the camera through the application's
  navigation, injected with attachNavigation({ run, subscribeHandoff }):
  aircraft and satellite tracking is released first, the cockpit refuses,
  and FOLLOW stops when another feature takes the camera. No UI imports
  in the layer.
- The mesh sampler follows the mesh floor's rules: it waits for the
  visible tileset to finish streaming (visibleTilesetLoaded, now exposed
  by the mesh floor service), needs a real bare-earth prior and keeps to
  the shared meshFloorSampleWithinPrior window, which cameraFollow now
  uses too. A cell is probed again once the camera is half as far from
  it (down to 40 m), so a coarse early sample is replaced and redrawn.
- The MCP globe panel's CSP allows the Mapillary Graph API and its image
  CDN (https://*.xx.fbcdn.net).
- The tile proxy reads bodies with the shared readResponseBytesCapped.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-06 23:04:33 +01:00
Said TurkseverandClaude Opus 5.5 d70f468781 fix(street-level): harden the Mapillary tile proxy
From gekh's review of #768, each with a test that fails before:

- The routes refuse cross-site requests (sameSiteGated, as the paid
  proxies do) and the tile route has a generous per-IP limit (600/min), so
  another page cannot burn the token's quota or trip the shared 429 hold.
- At most six upstream fetches run at once; a queued request that is
  abandoned never fetches, nor does one abandoned during the disk read.
- A body past the 48 MB cap aborts the upstream request as it streams.
- Empty tiles are charged against the memory and disk budgets.
- Each disk write uses its own temp file and a retrim is skipped while a
  write of that tile is pending, so concurrent hits cannot extend a tile's
  life or fail a rename.
- Upstream refusals other than 401/403/429 answer 502.
- The tile route's success path is tested end to end (200 with the image
  layer stripped and the right headers, 204 when empty, an abandoned
  response aborts upstream); the teardown race that made this file flaky
  is gone (240 parallel runs, no failure); the QA-constant tautologies are
  replaced by a check against the real provider registry; the boundary
  group lists the modules the provider actually imports.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-05 18:35:44 +01:00
Said Turksever 91d8bba4a3 Merge branch 'main' of https://github.com/bilawalsidhu/gods-eye-view into pr/mapillary-layer
# Conflicts:
#	CHANGELOG.md
#	README.md
2026-10-05 13:47:54 +01:00
manjunath22466 0343b4495e fix the remaining voice review gaps
keep analyst counts, speech, cards, cancellation, pointer capture, tool schema boundaries, and session lifetime consistent
add the exact Alps fallback and focused regression coverage
2026-10-05 04:37:28 +05:30
Said TurkseverandClaude Opus 5.5 7ae5f52c89 test(street-level): coverage race, camera framing and panel-control tests
From the test-engineering review of #768: the rendering and panel code had
thin unit coverage (coverage.js 29% of lines, sequences/viewer/selection
~30%, cameraFollow 50%, streetLevelControls only source-text checks), and
two shipped bugs were caught only by the manual browser gate.

- coverage.test.mjs drives the real createCoverage against a fake scene and
  a source whose tile requests the test resolves. It reproduces gekh's P0 #2:
  a request superseded by retire() finishes after a newer one for the same
  tile. Without the ownership checks it drops the newer request's key and a
  refresh starts a duplicate whose lines nothing can remove (fails on the old
  loadTile, passes now). It also covers the draped-to-cast swap keeping both
  line sets on the globe until the cast one is built and clear() removing
  both mid-swap, and a tile with nothing castable not being rebuilt.
- coverageFixture.mjs encodes Mapillary-shaped coverage tiles (sequence
  lines, overview points) from lon/lat; the tests and the hermetic gate use it.
- cameraFollow.test.mjs pins the underground-camera fix: a -14,886 m sample
  is ignored for bare earth, a plausible sample wins, and following stands at
  eye height. Three of the four fail on the pre-fix module (the first reports
  "centre at -14884 m").
- streetLevelControls.test.mjs is a contract test through the real
  DataLayerManager and LayerStateCoordinator: a 360 deg click and a SINCE
  release reach the durable layer state and the encoded share link under
  Street Level's token. Against a stand-in layer it also covers the chip rule
  (darkening the last lit chip turns the layer off, provider kept on; lighting
  a dark chip is a user params request, then enable), the legend rebuilding
  on a same-count swap (review #9) and the viewer resizing only on open
  (review #8). With the old direct-to-layer routing, three of these fail,
  including both share-link tests.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-04 23:50:21 +01:00
Bilawal Sidhu e7cb9b02b5 Merge main into feat/voice-core
Keeps the voice-core prompt rules and adds main's world-query and
vessels-vs-visuals rules; the tool catalog wraps the deixis-aware runner.

Also fixes two things the branch had before the merge:
- Live voice could not start: OpenAI rejects track_entity's top-level
  anyOf. Model-facing tools now omit top-level combinators; the runner
  and benchmark still require a query or a referent.
- The Contacts-centred analyst answer dropped the viewport coverage note.
2026-10-03 23:30:02 -07:00
Sameh Khamis e8e49a49e0 feat: ask for vessels by area
The vessel source accepts an optional area and sends it as lat, lon and
radius_km. The vessel layer asks for the area the camera shows (centered
on the middle of the screen, sized by camera height), or every vessel
from high enough up, and asks again when the view moves or zooms by a
quarter of that radius. vessels_in_area names its area too. Servers that
hold every vessel may ignore the area; callers still keep only what is
inside it.
2026-10-03 22:44:45 -07:00
Sameh Khamis a2099358fd chore: classify the tools/panel export
Add the tools-panel boundary group for the new export.
2026-10-03 21:20:04 -07:00
Said TurkseverandClaude Opus 5.5 5a7ce5785e Merge upstream/main (v0.2.1) into pr/mapillary-layer
Brings in 123 commits from main, including the v0.2.0 and v0.2.1 releases
(MCP server and tool catalog, server security hardening, build hygiene).

Conflicts:
- package.json: kept main's script order and added this PR's
  qa:panel-resize and qa:street-level; exports keep both sides (main's
  tools/view entries and this PR's street-level and Mapillary entries).
- src/tooling/viteBuild.test.mjs: kept this PR's Mapillary-token define
  assertion and main's new wildcard-host allowedHosts assertions.
- CHANGELOG.md: main now has release sections; this PR's entries go under
  [Unreleased].

Checks after the merge: doctor, format:check, check:boundaries,
layer-token:check (28 published, 1 new: street-level 0), npm test (5726
pass), build, the Windows job's focused tests (70 pass), qa:panel-resize,
and the keyless street-level gate. The new CSP allows Mapillary (https:
connect/img, blob workers). The keyed gate stops at coverage locally
because the dev .env Mapillary token is invalid (upstream 403), not because
of the merge.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-03 13:29:32 +01:00
Sameh KhamisandClaude Opus 5.5 6cdd6c8af9 refactor(server): share one proxy-header check across the local gates
localRequestGate.mjs owns the reverse-proxy header list and hasProxySignals;
Provider Settings, the cross-site gate and /mcp all use it instead of two
copies of the same nine names. The changelog credits the cross-site gate.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-10-02 20:02:48 -07:00
98b8c6c581 fix(server): keep the Host-header check when binding to all interfaces
Binding HOST=0.0.0.0 no longer sets Vite's allowedHosts to true. The dev and
preview servers accept IP addresses, localhost and the LAN hostnames listed
in GEV_ALLOWED_HOSTS; suffix and wildcard entries are ignored. The
configuration factory takes the resolved list as an input, so build/vite.js
still reads no environment.

Ported from #97 to the current build/vite.js layout. Fixes #21.

Co-authored-by: Sameh Khamis <[email protected]>
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-10-02 19:59:02 -07:00
7aa9bbd3be fix(server): gate cost/log endpoints against cross-site requests and ship a full CSP
The cost-bearing endpoints (/api/realtime/token, /api/openai/hud-summary,
/api/google/nearby-places) and the voice debug log refuse cross-site browser
requests: a foreign or opaque Origin, a Sec-Fetch-Site other than
same-origin/none, or proxy forwarding headers. Loopback tools without an
Origin and the LAN opt-in keep working. The dev and preview servers send one
shared Content-Security-Policy, and embed-mode framing rewrites only the
frame-ancestors directive of it.

Salvaged from #242 onto current main.

Co-authored-by: Sameh Khamis <[email protected]>
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-10-02 19:56:42 -07:00
Sameh Khamis 996b95eb45 Load the God's Eye View panel through the MCP server
Hosts serve panels from their own sites and may refuse other addresses;
Codex refuses any address on the user's machine. The panel now never
requests the app's server: it loads the app's panel build and data
through panel_request, a tool only the panel may call, which requests
the path from the app's server. One path in every host; only map
providers load directly.

npm run build:panel writes the panel build to dist/panel, served at
/panel/: one app script, one stylesheet, Cesium's script, and Cesium's
workers as one script Cesium runs from memory. Tools may now be marked
app-only. The panel CORS rules are gone.
2026-10-02 18:29:42 -07:00
Sameh Khamis 216a75ac71 feat: show views as the live globe in MCP Apps clients
show_on_globe replaces open_in_gods_eye_view and names an MCP Apps view, a
ui:// panel that loads the app in embed mode and posts each later view to it,
so the globe in the conversation changes without reloading. It also takes a
view another answer returned. Tools can declare a UI resource, and the MCP
adapter serves resources/list and resources/read and lists each tool's
resource in _meta.ui.resourceUri.
2026-10-02 15:21:36 -07:00
Sameh Khamis 60c40865e9 feat: add an embed mode that shows only the globe
?embed=1 shows the globe alone: clean view with the HUD, panels, welcome and
setup prompts hidden, and provider attribution kept. The page that frames it
sends views with postMessage; the app applies each through its own actions
and reports every step. Annotations in any link are drawn once it restores.
Only embed-mode documents may be framed; every other page keeps
X-Frame-Options DENY and frame-ancestors 'none', and
GEV_EMBED_FRAME_ANCESTORS can restrict who frames them.
2026-10-02 15:21:36 -07:00
Sameh Khamis d6473b6049 feat: return the view that shows each answer
Tool answers with something to show now include data.view: the view with
the matching layers on, the area framed from above or a single aircraft or
satellite followed, and the link that opens it. Area framing moves to
src/tools/views.js so links and answers frame alike.
2026-10-02 15:21:36 -07:00
Sameh Khamis 96a8a9addb feat: describe what the app shows as a view
A view is a camera, data layers, visual style, map imagery and an aircraft,
military aircraft or satellite to follow, written in the share-link format
the app already restores. gods-eye-view/view builds, encodes and decodes one,
and share links take their style names from it. open_in_gods_eye_view now
builds its link from a full view: an area or camera, layers, style, map and
something to follow.
2026-10-02 15:21:36 -07:00
Sameh Khamis cac5ba3b72 fix: derive HUD caption feed states from section results
The caption request declared every answered section nominal, so a stale
aircraft snapshot reached the caption as live. Each section now reports
stale or unavailable from its own result, and the provenance envelope is
built with the app's feedProvenanceEnvelope.
2026-10-02 15:21:36 -07:00
Sameh Khamis 853c60583f fix: report stale transit feeds and drop expired positions
get_transit_vehicles returned positions from a feed the proxy served from
its error cache, and hour-old fixes, as current. It now applies the transit
layer's rules: a feed is stale when the proxy says so or the operator has
not answered recently, and fixes older than the vehicle limit are dropped
and counted.
2026-10-02 15:21:36 -07:00
Said TurkseverandClaude Opus 5.5 514788303d feat(street-level): refine ground casting with the Google 3D surface
The raycast challenge on #768 showed bare-earth casting misplacing roads
that are not at grade: lines floated over freeways in trenches and steep
streets (rendered line pixels floating: Austin 8.5%, SF 27.1%, LA 43.8%),
because a ~111 m terrain grid cannot see a 30 m-wide cut or a slope between
its corners.

meshSampler.js samples the rendered Google 3D surface (scene.sampleHeight,
overlays excluded) once per ~11 m cell within 900 m of the camera, nearest
first, in idle time within a 6 ms budget; misses are retried, not latched.
groundCast.refineHeights blends it in, per point along a line:
- mesh up to 3 m above bare earth is the road: follow it, 1 m above;
- higher mesh (canopy, deck, roof): carry the road's offset from bare earth
  across from the road samples on both sides (up to 8 points);
- otherwise bare earth + 2 m, as before.
Lines, cones and the marker use it; tiles touched by new samples are
redrawn one per idle slice with the no-blink swap.

Rendered line pixels on the surface / floating, before -> after:
Austin 90.0 -> 95.3% / 8.5 -> 0.7%; SF 69.0 -> 86.4% / 27.1 -> 9.1%;
LA 52.3 -> 91.0% / 43.8 -> 4.0%; Innsbruck 95.0 -> 95.7% / 0.2 -> 0.2%;
Sacramento 80.7 -> 79.3% / 3.8 -> 2.7%; buried lines stay under 1%.
Cones floating in SF 44 -> 5%, buried at LA 59 -> 28%. Main-thread long
tasks added during refinement: at most 134 ms (Austin, densest tile).
Roads on elevated decks are still drawn at ground level under the deck.

Unit tests cover the blend (trench, slope, canopy bridge, deck, bad probe),
the finer cast with meshAt, and the sampler (once per cell, nearest first,
overlays excluded, far cells skipped, misses not latched, idle when off).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-02 01:43:16 +01:00
Said TurkseverandClaude Opus 5.5 e01ffb3cad fix: restore the commas the main merge dropped from two JSON lists
The merge of main (c451478) appended main's new entries directly after
this branch's last entries in scripts/format-scope.json (after
streetLevel/index.test.mjs) and in two groups of
scripts/package-boundaries.json (after app/layers/streetLevel.js), without
the separating comma. Both files stopped parsing, so every CI job failed
at its first JSON read, the "Check adopted formatting" step.

With the commas back, the CI steps pass locally: doctor, format:check,
check:boundaries, layer-token:check against main, npm test (5475 pass),
build, and the Windows job's focused onboarding tests.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-02 00:48:01 +01:00
Sameh Khamis df0e0f32e8 feat: choose per tool whether MCP, voice or both offer it
src/tools/surfaces.js lists the tools a surface leaves out, and the MCP
server, the voice session's tool list and the browser catalog voice calls
all filter through it. Voice leaves out tools that answer with images, link
to the app, or repeat what its app actions already answer.
2026-10-01 14:36:12 -07:00
Sameh Khamis 1a03e7483d feat: share the tool catalog with voice 2026-10-01 13:52:36 -07:00
Sameh Khamis 0953ebb026 feat: add a Bhote Koshi flood event tool 2026-10-01 13:44:41 -07:00
Sameh Khamis 28cfd39d1a feat: add a datacenter and dam tool 2026-10-01 13:38:38 -07:00
Sameh Khamis a8e5ff9390 refactor: move infrastructure data parsing into a portable source module
The datacenter and dam layers parsed their bundled GeoJSON Lines and
built analyst records inside the Cesium-backed layer module. Move the
data URLs, the line parser, mapAnalystRecord and layerTitle unchanged to
src/sources/infrastructureData.js; the layer module imports them and
still exports mapAnalystRecord. The consumer-build pin lists the new
module.
2026-10-01 13:34:26 -07:00
Sameh Khamis 0a454815cb feat: add a license plate reader camera tool
Add find_alpr_cameras over the layer's OpenStreetMap camera extracts:
cameras in a US or Canadian area of at most 3° per side, nearest first,
with operator, manufacturer and facing direction, and the source's
attribution. Areas outside coverage or too wide are reported.
2026-10-01 13:31:31 -07:00
Sameh Khamis c1957d884e feat: add a submarine cable tool
Add find_submarine_cables over the bundled TeleGeography data: cables
passing through or landing in an area, or matching a name, with landing
points and the dataset's attribution. The local MCP server's fetch reads
the bundled data files a browser would load by URL, and nothing outside
that directory.
2026-10-01 13:28:02 -07:00
Sameh Khamis 9be90fff44 feat: add a recent satellite imagery tool
Add get_recent_imagery. It searches the recent Harmonized Landsat and
Sentinel-2 catalog for an area, picks the image the layer would show
with the layer's own ranking, and returns it with its date, sensor and
cloud cover, falling back to the VIIRS daily overview.
2026-10-01 13:25:00 -07:00
Sameh Khamis a3aa058569 feat: add weather map and wind tools
Add get_weather_map, which returns the latest NOAA radar, satellite or
lightning map over an area as an image, choosing a window the image
route accepts and reporting areas outside the product's coverage, and
get_wind, which samples GFS or IFS wind at a location with the wind
layer's own grid sampling.
2026-10-01 13:22:16 -07:00
Sameh Khamis fe69f22346 feat: turn layers on in links to an area
open_in_gods_eye_view accepts layers and writes them with the app's own
share-link layer codec, so the link opens with those layers on. Layer
names are limited to the registered layer ids.
2026-10-01 13:17:15 -07:00
Sameh Khamis 9de2705eaf refactor: move the layer state coordinator into its own module
layerState.js held both the share-link layer codec and the coordinator
that restores layer choices into the running app and persists them to
browser storage. Move the coordinator, unchanged, to
layerStateCoordinator.js so the codec stays a pure data module that code
outside the browser can use to write share links. The registry stays in
layerState.js, where the token tooling reads it, and the aircraft
barrel re-exports both.
2026-10-01 13:16:19 -07:00
Sameh Khamis a8b5860e9f refactor: share the default tool services between surfaces
Move the composition of the default tool services from the Node MCP
server into gods-eye-view/tools/services, a portable export. Given a
fetch that resolves the sources' /api paths, it builds the same services
in a browser as on the local MCP server, so other surfaces can compose
the same catalog. Queries still read only their services.
2026-10-01 13:12:34 -07:00
Sameh Khamis b6af8b34e0 feat: add a tool that links to an area in the app
Add open_in_gods_eye_view. It builds a version 2 share link looking
straight down on an area, with altitude chosen from the area's size, on
the app address the application supplies.
2026-10-01 12:42:08 -07:00
Sameh Khamis e6cbcc31ad feat: add ship tools
Add vessels_in_area, find_vessel and get_vessel_track over the live
vessel source, and a ships section in situation_brief. Without an AIS
key the source's own message reaches clients as an unavailable feed.
2026-10-01 12:32:09 -07:00
Sameh Khamis 0a74e36ce8 feat: add weather, hazard, terrain and situation tools
Add get_weather, get_regional_brief, get_cyclones, get_fire_perimeters,
get_terrain_height, find_military_installations and get_map_features
over the application request services and the layers' sources.

situation_brief combines weather, earthquakes, fires, aircraft and
cyclones for an area by reusing those tools, marking sections that are
unavailable instead of failing. get_hud_caption returns the app's
heads-up display caption for the same overview.
2026-10-01 12:28:34 -07:00
Sameh Khamis 8c97fed92d feat: add bike-share and transit tools
Add get_bike_share over the public GBFS systems and get_transit_vehicles
over the GTFS-Realtime feeds. Each finds the systems or feeds whose
coverage reaches the area, reads up to three, and reports any that were
unavailable instead of failing the whole answer. Transit results carry
each feed's attribution and license.
2026-10-01 12:22:13 -07:00
Sameh Khamis eb12303f46 refactor: move GBFS station parsing into a portable source module
The bike-share layer parsed station documents inside its model factory.
Move the parsers unchanged to src/sources/gbfsStations.js and have the
model import them, so code outside the layer can read GBFS stations
without constructing the layer.
2026-10-01 12:18:48 -07:00
Sameh Khamis e680a59bf5 feat: add place search and routing tools
Add search_places and places_nearby over the app's Google Places routes,
and plan_route over its OpenStreetMap routing. The place search service
reports when no search key is configured, so an unconfigured server is
not mistaken for an empty result, and rate limits become retry_later.
Route endpoints accept a place name or coordinates.
2026-10-01 12:16:01 -07:00
Sameh Khamis 85fee59da1 feat: add public camera and radio tools
Add find_cctv_cameras, get_cctv_snapshot and find_radio_stations. A
snapshot returns the camera's current frame as image content with its
credit. Tool results may now carry base64 images, which the MCP adapter
sends as image content.
2026-10-01 12:11:00 -07:00
Sameh Khamis 22c3fe40b0 feat: add aviation and satellite tools
Add aircraft_in_area, find_aircraft, get_aircraft_track and
get_aircraft_info over the live aircraft sources, with an optional
military feed, and next_satellite_pass and satellites_overhead over the
satellite catalog and the existing pass predictor.

Source failures from the live contract now become tool errors with the
matching code, so a rate limit reaches clients as retry_later with a
wait time. Tool schemas may use pattern.
2026-10-01 12:05:50 -07:00
Sameh Khamis 9895942633 refactor: move TLE text parsing into a portable source module
The satellites layer parsed catalog text inside its Cesium-backed orbit
owner. Move the parser unchanged to src/sources/tle.js, add a catalog
number helper, and have the layer delegate to it so code outside the
layer can read TLE text without loading rendering.
2026-10-01 12:05:41 -07:00
Sameh Khamis c3dfa8e853 feat: add a tool catalog and local MCP server
Define tools that answer questions from the app's data once, independent
of the surface that exposes them. A tool declares its arguments and the
services it reads; applications compose tools with their own services and
optional call interceptors. Queries reuse the layers' portable source
factories, so they run wherever an application routes /api requests.

The first queries are get_earthquakes, get_active_fires and
get_recent_launches, with a shared area argument (place name, bounding
box, or point and radius) and capped lists.

gods-eye-view/tools/mcp adapts a catalog to the Model Context Protocol
with a small JSON-RPC handler and a stateless HTTP transport, adding no
dependencies. npm run mcp serves Core's tools over stdio to local clients
such as Claude Code, reading from a running app. Both exports are
portable and checked by check:boundaries; the app does not import them.
2026-10-01 11:51:59 -07:00