style: apply current runtime formatter to voice integration

This commit is contained in:
Bilawal Sidhu committed 2026-09-15 10:54:32 -05:00
1 parent 3385e6b713
commit d1a72a35af
4 files changed
+414 -249

No files matched your search

+71 -14
View File
@@ -29,14 +29,54 @@ import { pointInRing } from './naturalEarthRegions.js';
/** Layers the engine understands, with the fields queries may reference. */ /** Layers the engine understands, with the fields queries may reference. */
export const ANALYST_LAYERS = { export const ANALYST_LAYERS = {
flights: { numeric: ['altitudeM', 'speedMps', 'verticalRateMps'], text: ['callsign', 'icao24', 'originCountry', 'operator', 'routeOrigin', 'routeDestination', 'aircraftClass'], flags: ['military', 'onGround'] }, flights: {
military: { numeric: ['altitudeM', 'speedMps', 'verticalRateMps'], text: ['callsign', 'icao24', 'originCountry', 'operator', 'aircraftClass'], flags: ['military', 'onGround'] }, numeric: ['altitudeM', 'speedMps', 'verticalRateMps'],
'ais-live-vessels': { numeric: ['speedKts', 'courseDeg'], text: ['name', 'mmsi', 'shipType', 'destination', 'navStatus'], flags: [] }, text: [
'local-firms': { numeric: ['frp'], text: ['confidence', 'satellite'], flags: [] }, 'callsign',
earthquakes: { numeric: ['magnitude', 'depthKm'], text: ['place'], flags: [] }, 'icao24',
satellites: { numeric: ['altitudeM', 'speedMps'], text: ['name', 'noradId', 'satelliteClass', 'group'], flags: [] }, 'originCountry',
'local-datacenters': { numeric: [], text: ['name', 'operator', 'capacity'], flags: [] }, 'operator',
'local-dams': { numeric: [], text: ['name', 'operator', 'river', 'output'], flags: [] }, 'routeOrigin',
'routeDestination',
'aircraftClass',
],
flags: ['military', 'onGround'],
},
military: {
numeric: ['altitudeM', 'speedMps', 'verticalRateMps'],
text: ['callsign', 'icao24', 'originCountry', 'operator', 'aircraftClass'],
flags: ['military', 'onGround'],
},
'ais-live-vessels': {
numeric: ['speedKts', 'courseDeg'],
text: ['name', 'mmsi', 'shipType', 'destination', 'navStatus'],
flags: [],
},
'local-firms': {
numeric: ['frp'],
text: ['confidence', 'satellite'],
flags: [],
},
earthquakes: {
numeric: ['magnitude', 'depthKm'],
text: ['place'],
flags: [],
},
satellites: {
numeric: ['altitudeM', 'speedMps'],
text: ['name', 'noradId', 'satelliteClass', 'group'],
flags: [],
},
'local-datacenters': {
numeric: [],
text: ['name', 'operator', 'capacity'],
flags: [],
},
'local-dams': {
numeric: [],
text: ['name', 'operator', 'river', 'output'],
flags: [],
},
}; };
const EARTH_R_KM = 6371; const EARTH_R_KM = 6371;
@@ -131,7 +171,7 @@ export function createAnalystEngine(providers) {
async function query(spec = {}) { async function query(spec = {}) {
const layers = const layers =
spec.followUp && lastResult spec.followUp && lastResult
? null // follow-up: re-filter the remembered set, no re-snapshot ? null // follow-up: re-filter the remembered set, no re-snapshot
: Array.isArray(spec.layers) && spec.layers.length : Array.isArray(spec.layers) && spec.layers.length
? spec.layers ? spec.layers
: ['flights']; : ['flights'];
@@ -161,7 +201,20 @@ export function createAnalystEngine(providers) {
const rows = providers.getRecords(key) || []; const rows = providers.getRecords(key) || [];
const snapshot = providers.getLayerSnapshot?.(key); const snapshot = providers.getLayerSnapshot?.(key);
if (snapshot) queriedSnapshots.push(snapshot); if (snapshot) queriedSnapshots.push(snapshot);
layersQueried.push({ layerKey: key, records: rows.length, ...(snapshot ? { feedState: snapshot.feedState, source: snapshot.source, lastUpdate: snapshot.lastUpdate, enabled: snapshot.enabled, error: snapshot.error } : {}), ...providers.getRecordCoverage?.(key, rows) }); layersQueried.push({
layerKey: key,
records: rows.length,
...(snapshot
? {
feedState: snapshot.feedState,
source: snapshot.source,
lastUpdate: snapshot.lastUpdate,
enabled: snapshot.enabled,
error: snapshot.error,
}
: {}),
...providers.getRecordCoverage?.(key, rows),
});
for (const row of rows) records.push({ layerKey: key, ...row }); for (const row of rows) records.push({ layerKey: key, ...row });
} }
} }
@@ -206,8 +259,8 @@ export function createAnalystEngine(providers) {
// nothing in the payload to show which. // nothing in the payload to show which.
const subjectCenter = const subjectCenter =
Number.isFinite(subject?.lat) && Number.isFinite(subject?.lon) Number.isFinite(subject?.lat) && Number.isFinite(subject?.lon)
? { lat: subject.lat, lon: subject.lon } ? { lat: subject.lat, lon: subject.lon }
: null; : null;
const center = explicitCenter || const center = explicitCenter ||
subjectCenter || { lat: view.lat, lon: view.lon }; subjectCenter || { lat: view.lat, lon: view.lon };
resolvedScope = { center, km: Number(scope.km) || 100 }; resolvedScope = { center, km: Number(scope.km) || 100 };
@@ -273,9 +326,13 @@ export function createAnalystEngine(providers) {
coverage: { coverage: {
layersQueried, layersQueried,
scope: scopeNote, scope: scopeNote,
...(queriedSnapshots.length ? { feedProvenance: feedProvenanceEnvelope(queriedSnapshots) } : {}), ...(queriedSnapshots.length
? { feedProvenance: feedProvenanceEnvelope(queriedSnapshots) }
: {}),
followUp: Boolean(spec.followUp && lastResult), followUp: Boolean(spec.followUp && lastResult),
note: layersQueried.some((layer) => layer.basis === 'bounded-loaded-records') note: layersQueried.some(
(layer) => layer.basis === 'bounded-loaded-records',
)
? 'Counts and ranks cover the bounded examined loaded records only; omitted records may change the nearest item or count. Satellite distance is ground distance, not slant range.' ? 'Counts and ranks cover the bounded examined loaded records only; omitted records may change the nearest item or count. Satellite distance is ground distance, not slant range.'
: 'client-side data only — answers cover what the enabled layers currently hold', : 'client-side data only — answers cover what the enabled layers currently hold',
}, },
+25 -8
View File
@@ -24,7 +24,12 @@ import {
geoidHeight, geoidHeight,
} from './data/geoid.js'; } from './data/geoid.js';
import { getBasemapLabelContext } from './voice/gevActions.js'; import { getBasemapLabelContext } from './voice/gevActions.js';
import { hudSummaryMatchesProvenance, hudSummaryLayerContext, hudTelemetryProvenanceTag, isHudSummaryUnconfigured } from './hudSummaryResponse.js'; import {
hudSummaryMatchesProvenance,
hudSummaryLayerContext,
hudTelemetryProvenanceTag,
isHudSummaryUnconfigured,
} from './hudSummaryResponse.js';
/** Color palettes keyed by shader mode; applied as CSS custom properties. */ /** Color palettes keyed by shader mode; applied as CSS custom properties. */
const HUD_COLORS = { const HUD_COLORS = {
@@ -641,15 +646,17 @@ export class IntelHUD {
const altDisplayM = Number.isFinite(m.altMslM) ? m.altMslM : m.altM; const altDisplayM = Number.isFinite(m.altMslM) ? m.altMslM : m.altM;
const altTag = const altTag =
altDisplayM >= 1000 altDisplayM >= 1000
? `${(altDisplayM / 1000).toFixed(1)}KM` ? `${(altDisplayM / 1000).toFixed(1)}KM`
: `${Math.round(altDisplayM)}M`; : `${Math.round(altDisplayM)}M`;
const winTag = window const winTag = window
? `${Math.max(1, Math.round(window.widthKm))}x${Math.max(1, Math.round(window.heightKm))}KM` ? `${Math.max(1, Math.round(window.widthKm))}x${Math.max(1, Math.round(window.heightKm))}KM`
: 'N/A'; : 'N/A';
// NEAR the nearest catalogued POI at metro range; otherwise the lat/lon sector. // NEAR the nearest catalogued POI at metro range; otherwise the lat/lon sector.
const localityTag = composeLocalityTag(nearest, m.latDeg, m.lonDeg); const localityTag = composeLocalityTag(nearest, m.latDeg, m.lonDeg);
const provenance = hudTelemetryProvenanceTag(this._dataManager?.getAll?.() || []); const provenance = hudTelemetryProvenanceTag(
this._dataManager?.getAll?.() || [],
);
const line = `${modeLabel} ${band} ${localityTag} | ${region} | ALT ${altTag} | WINDOW ${winTag} | SUN ${m.sunEl.toFixed(0)}° | ONA ${m.ona.toFixed(0)}° | ${localTag}`; const line = `${modeLabel} ${band} ${localityTag} | ${region} | ALT ${altTag} | WINDOW ${winTag} | SUN ${m.sunEl.toFixed(0)}° | ONA ${m.ona.toFixed(0)}° | ${localTag}`;
return provenance ? `${line} | ${provenance}` : line; return provenance ? `${line} | ${provenance}` : line;
} }
@@ -736,7 +743,12 @@ export class IntelHUD {
if (!response.ok || !data?.summary) { if (!response.ok || !data?.summary) {
throw new Error(data?.error || `HTTP ${response.status}`); throw new Error(data?.error || `HTTP ${response.status}`);
} }
this._setSummaryText(hudSummaryMatchesProvenance(data.summary, context.feedProvenance) ? data.summary : fallbackText, animate); this._setSummaryText(
hudSummaryMatchesProvenance(data.summary, context.feedProvenance)
? data.summary
: fallbackText,
animate,
);
} catch (error) { } catch (error) {
if (error?.name !== 'AbortError') { if (error?.name !== 'AbortError') {
console.warn('[HUD] AI summary unavailable:', error); console.warn('[HUD] AI summary unavailable:', error);
@@ -770,8 +782,8 @@ export class IntelHUD {
const enabledLayers = const enabledLayers =
this._dataManager this._dataManager
?.getAll?.() ?.getAll?.()
?.filter((layer) => layer.enabled) ?.filter((layer) => layer.enabled)
.map((layer) => layer.name) || []; .map((layer) => layer.name) || [];
return { return {
placeLabels: labels.placeLabels, placeLabels: labels.placeLabels,
streetLabels: labels.streetLabels, streetLabels: labels.streetLabels,
@@ -907,7 +919,12 @@ export class IntelHUD {
this._dataManager = dataManager || null; this._dataManager = dataManager || null;
if (typeof this._dataManager?.subscribe === 'function') { if (typeof this._dataManager?.subscribe === 'function') {
this._dataManagerUnsubscribe = this._dataManager.subscribe((change) => { this._dataManagerUnsubscribe = this._dataManager.subscribe((change) => {
if (['visibility', 'refresh-transition', 'refresh-cancelled'].includes(change?.type)) this._markSummaryDirty(); if (
['visibility', 'refresh-transition', 'refresh-cancelled'].includes(
change?.type,
)
)
this._markSummaryDirty();
}); });
} }
this._markSummaryDirty(); this._markSummaryDirty();
+9 -4
View File
@@ -30,8 +30,8 @@ export function keylessHudSummaryResponse(apiKey) {
export function isHudSummaryUnconfigured(status, data) { export function isHudSummaryUnconfigured(status, data) {
const keys = const keys =
data !== null && typeof data === 'object' && !Array.isArray(data) data !== null && typeof data === 'object' && !Array.isArray(data)
? Object.keys(data) ? Object.keys(data)
: []; : [];
return ( return (
keys.length === 4 && keys.length === 4 &&
status === 200 && status === 200 &&
@@ -93,7 +93,9 @@ export function hudTelemetryProvenanceTag(layers = [], options) {
const envelope = feedProvenanceEnvelope(snapshots, options); const envelope = feedProvenanceEnvelope(snapshots, options);
if (!envelope.overall || envelope.overall === 'nominal') return null; if (!envelope.overall || envelope.overall === 'nominal') return null;
const names = envelope.layers const names = envelope.layers
.filter((s) => s.feedState && s.feedState !== 'nominal' && s.feedState !== 'off') .filter(
(s) => s.feedState && s.feedState !== 'nominal' && s.feedState !== 'off',
)
.map((s) => String(s.name || s.id || 'LAYER').toUpperCase()) .map((s) => String(s.name || s.id || 'LAYER').toUpperCase())
.slice(0, 2); .slice(0, 2);
return `${envelope.overall.toUpperCase()}${names.length ? ` ${names.join('/')}` : ''}`; return `${envelope.overall.toUpperCase()}${names.length ? ` ${names.join('/')}` : ''}`;
@@ -103,5 +105,8 @@ export function hudTelemetryProvenanceTag(layers = [], options) {
export function hudSummaryMatchesProvenance(summary, provenance) { export function hudSummaryMatchesProvenance(summary, provenance) {
const state = provenance?.overall; const state = provenance?.overall;
if (!state || state === 'nominal' || state === 'off') return true; if (!state || state === 'nominal' || state === 'off') return true;
return String(summary || '').toUpperCase().split(/\W+/).includes(String(state).toUpperCase()); return String(summary || '')
.toUpperCase()
.split(/\W+/)
.includes(String(state).toUpperCase());
} }
+309 -223
View File
@@ -1,4 +1,8 @@
import { layerSnapshot, layerSnapshots, feedProvenanceEnvelope } from '../data/layerSnapshot.js'; import {
layerSnapshot,
layerSnapshots,
feedProvenanceEnvelope,
} from '../data/layerSnapshot.js';
import { readLayerLifecycleSummary } from './layerSummary.js'; import { readLayerLifecycleSummary } from './layerSummary.js';
export { readLayerLifecycleSummary } from './layerSummary.js'; export { readLayerLifecycleSummary } from './layerSummary.js';
import { defaultGeospatial } from '../search/defaults.js'; import { defaultGeospatial } from '../search/defaults.js';
@@ -300,7 +304,7 @@ function cachesFor(service) {
service.signal?.addEventListener( service.signal?.addEventListener(
'abort', 'abort',
() => { () => {
for (const cache of Object.values(caches)) cache.clear(); for (const cache of Object.values(caches)) cache.clear();
}, },
{ once: true }, { once: true },
); );
@@ -519,16 +523,16 @@ export function createGevActionRunner({
...(args.locationQuery ? { query: args.locationQuery } : {}), ...(args.locationQuery ? { query: args.locationQuery } : {}),
...(hasCoordinates ...(hasCoordinates
? { ? {
latitude: Number(args.latitude), latitude: Number(args.latitude),
longitude: Number(args.longitude), longitude: Number(args.longitude),
} }
: {}), : {}),
}; };
const layer = await runGevAction( const layer = await runGevAction(
'set_layer_visibility', 'set_layer_visibility',
{ {
layerId, layerId,
enabled: true, enabled: true,
}, },
runOptions, runOptions,
); );
@@ -712,10 +716,10 @@ export function createGevActionRunner({
} }
const cancellationState = () => const cancellationState = () =>
withContextModeVocabulary( withContextModeVocabulary(
typeof styleManager.getContextModeState === 'function' typeof styleManager.getContextModeState === 'function'
? styleManager.getContextModeState() ? styleManager.getContextModeState()
: {}, : {},
); );
if (!current()) { if (!current()) {
return { return {
ok: false, ok: false,
@@ -731,8 +735,8 @@ export function createGevActionRunner({
const result = await styleManager.setContextMode( const result = await styleManager.setContextMode(
mode === 'off' ? null : mode, mode === 'off' ? null : mode,
{ {
signal: runOptions.signal, signal: runOptions.signal,
isCurrent: runOptions.isCurrent, isCurrent: runOptions.isCurrent,
}, },
); );
if (!current() && result?.ok !== true) { if (!current() && result?.ok !== true) {
@@ -803,8 +807,8 @@ export function createGevActionRunner({
rollbackTarget = styleManager.getAircraftTrackingTarget?.() || null; rollbackTarget = styleManager.getAircraftTrackingTarget?.() || null;
const contextState = const contextState =
typeof styleManager.getContextModeState === 'function' typeof styleManager.getContextModeState === 'function'
? styleManager.getContextModeState() ? styleManager.getContextModeState()
: {}; : {};
priorContextMode = contextState?.mode || null; priorContextMode = contextState?.mode || null;
const contactsReady = const contactsReady =
contextState?.mode === 'flights' && contextState?.mode === 'flights' &&
@@ -824,8 +828,8 @@ export function createGevActionRunner({
if (contextResult?.ok !== true || !current()) { if (contextResult?.ok !== true || !current()) {
const contextRollback = contextChangedForEntry const contextRollback = contextChangedForEntry
? await styleManager.setContextMode(priorContextMode, { ? await styleManager.setContextMode(priorContextMode, {
claimVisualAuthority: false, claimVisualAuthority: false,
}) })
: null; : null;
return { return {
ok: false, ok: false,
@@ -873,12 +877,12 @@ export function createGevActionRunner({
const contextRollback = await styleManager.setContextMode( const contextRollback = await styleManager.setContextMode(
priorContextMode, priorContextMode,
{ {
// Undoing this action's own precondition — still choreography. // Undoing this action's own precondition — still choreography.
claimVisualAuthority: false, claimVisualAuthority: false,
...(current() ...(current()
? { ? {
signal: runOptions.signal, signal: runOptions.signal,
isCurrent: runOptions.isCurrent, isCurrent: runOptions.isCurrent,
} }
: {}), : {}),
}, },
@@ -896,8 +900,8 @@ export function createGevActionRunner({
setPanelOpen(styleManager, 'data-panel', true); setPanelOpen(styleManager, 'data-panel', true);
const focusedLayer = const focusedLayer =
layerId && dataManager.layers.has(layerId) layerId && dataManager.layers.has(layerId)
? focusDataLayerRow(layerId) ? focusDataLayerRow(layerId)
: null; : null;
return { return {
ok: true, ok: true,
action: 'show_data_layers_menu', action: 'show_data_layers_menu',
@@ -907,10 +911,10 @@ export function createGevActionRunner({
.getAll() .getAll()
.filter((layer) => layer.showInTogglePanel !== false) .filter((layer) => layer.showInTogglePanel !== false)
.map((layer) => ({ .map((layer) => ({
id: layer.id, id: layer.id,
name: layer.name, name: layer.name,
enabled: layer.enabled, enabled: layer.enabled,
count: layer.stats?.count || 0, count: layer.stats?.count || 0,
})), })),
}; };
} }
@@ -924,16 +928,16 @@ export function createGevActionRunner({
typeof styleManager?.runImmediateLocationNavigation === 'function' typeof styleManager?.runImmediateLocationNavigation === 'function'
? (navigate) => ? (navigate) =>
styleManager.runImmediateLocationNavigation(navigate) styleManager.runImmediateLocationNavigation(navigate)
: null, : null,
beginDeferred: beginDeferred:
typeof styleManager?.beginDeferredLocationNavigation === 'function' typeof styleManager?.beginDeferredLocationNavigation === 'function'
? () => styleManager.beginDeferredLocationNavigation() ? () => styleManager.beginDeferredLocationNavigation()
: null, : null,
reassertDeferred: reassertDeferred:
typeof styleManager?.reassertDeferredLocationNavigation === 'function' typeof styleManager?.reassertDeferredLocationNavigation === 'function'
? (generation) => ? (generation) =>
styleManager.reassertDeferredLocationNavigation(generation) styleManager.reassertDeferredLocationNavigation(generation)
: null, : null,
onStart: () => { onStart: () => {
if (typeof styleManager?.beginLocationNavigation === 'function') { if (typeof styleManager?.beginLocationNavigation === 'function') {
styleManager.beginLocationNavigation(); styleManager.beginLocationNavigation();
@@ -1180,8 +1184,8 @@ function sanitizeAnnotationSpec(spec) {
out.points = out.points out.points = out.points
.slice(0, MAX_ROUTE_POINTS) .slice(0, MAX_ROUTE_POINTS)
.map((p) => .map((p) =>
p && typeof p === 'object' && typeof p.target === 'string' p && typeof p === 'object' && typeof p.target === 'string'
? { ...p, target: clampStr(p.target, MAX_TARGET_LEN) } ? { ...p, target: clampStr(p.target, MAX_TARGET_LEN) }
: p, : p,
); );
} }
@@ -1644,8 +1648,8 @@ export async function controlRadio(
// viewport's nearest station. // viewport's nearest station.
const action = const action =
requestedAction === 'play' && hasSelectionCriteria requestedAction === 'play' && hasSelectionCriteria
? 'select' ? 'select'
: requestedAction; : requestedAction;
const readRadioLifecycle = () => const readRadioLifecycle = () =>
readLayerLifecycleSummary(dataManager, 'radio'); readLayerLifecycleSummary(dataManager, 'radio');
@@ -1666,11 +1670,11 @@ export async function controlRadio(
const intentSummary = () => const intentSummary = () =>
lastIntentOutcome lastIntentOutcome
? { ? {
phase: lastIntentOutcome.phase, phase: lastIntentOutcome.phase,
cancellationReason: lastIntentOutcome.cancellationReason || null, cancellationReason: lastIntentOutcome.cancellationReason || null,
successorIntentEpoch: lastIntentOutcome.successorIntentEpoch ?? null, successorIntentEpoch: lastIntentOutcome.successorIntentEpoch ?? null,
successorEnabled: lastIntentOutcome.successorEnabled ?? null, successorEnabled: lastIntentOutcome.successorEnabled ?? null,
successorOrigin: lastIntentOutcome.successorOrigin ?? null, successorOrigin: lastIntentOutcome.successorOrigin ?? null,
} }
: {}; : {};
@@ -1832,7 +1836,7 @@ export async function controlRadio(
{ volume: volumePct / 100 }, { volume: volumePct / 100 },
{ origin: 'voice' }, { origin: 'voice' },
) )
: radio.setVolume(volumePct / 100); : radio.setVolume(volumePct / 100);
if (volumeApplied === false) { if (volumeApplied === false) {
return { return {
ok: false, ok: false,
@@ -1970,12 +1974,12 @@ export async function controlRadio(
if (!radioActionIsCurrent(options)) return cancelled(summarize); if (!radioActionIsCurrent(options)) return cancelled(summarize);
const station = radio.selectRequestedStation?.( const station = radio.selectRequestedStation?.(
{ {
categoryId: String(args.category || 'all'), categoryId: String(args.category || 'all'),
anchor: location ? { lat: location.lat, lon: location.lon } : null, anchor: location ? { lat: location.lat, lon: location.lon } : null,
country: normalizedCountry.empty country: normalizedCountry.empty
? String(location?.country || '') ? String(location?.country || '')
: normalizedCountry.code, : normalizedCountry.code,
stationQuery: String(args.stationQuery || ''), stationQuery: String(args.stationQuery || ''),
}, },
{ autoplay: false }, { autoplay: false },
); );
@@ -2097,23 +2101,23 @@ async function trackEntity(viewer, dataManager, styleManager, args = {}) {
'fire', 'fire',
'track_entity', 'track_entity',
() => { () => {
flyToLandmark(viewer, strongest.latitude, strongest.longitude, { flyToLandmark(viewer, strongest.latitude, strongest.longitude, {
range: 14000, range: 14000,
pitch: -50, pitch: -50,
heading: 0, heading: 0,
buildingHeight: 0, buildingHeight: 0,
duration: 2.2, duration: 2.2,
}); });
return { return {
ok: true, ok: true,
action: 'track_entity', action: 'track_entity',
kind: 'fire', kind: 'fire',
layerId: 'local-firms', layerId: 'local-firms',
label: strongest.label || 'Strongest fire', label: strongest.label || 'Strongest fire',
latitude: strongest.latitude, latitude: strongest.latitude,
longitude: strongest.longitude, longitude: strongest.longitude,
frp: strongest.frp ?? null, frp: strongest.frp ?? null,
}; };
}, },
); );
} }
@@ -2152,39 +2156,39 @@ async function trackEntity(viewer, dataManager, styleManager, args = {}) {
family.kind, family.kind,
'track_entity', 'track_entity',
() => { () => {
let trackedOk = false; let trackedOk = false;
if (family.kind === 'vessel') { if (family.kind === 'vessel') {
trackedOk = !!module.selectById?.(found.mmsi); trackedOk = !!module.selectById?.(found.mmsi);
flyToLandmark(viewer, found.latitude, found.longitude, { flyToLandmark(viewer, found.latitude, found.longitude, {
range: 6000, range: 6000,
pitch: -45, pitch: -45,
heading: 0, heading: 0,
buildingHeight: 0, buildingHeight: 0,
duration: 2.0, duration: 2.0,
}); });
} else if (family.kind === 'satellite') { } else if (family.kind === 'satellite') {
trackedOk = !!module.trackById?.(found.noradId, { origin: 'voice' }); trackedOk = !!module.trackById?.(found.noradId, { origin: 'voice' });
} else { } else {
trackedOk = !!module.trackById?.(found.icao24, { origin: 'voice' }); trackedOk = !!module.trackById?.(found.icao24, { origin: 'voice' });
} }
return { return {
ok: trackedOk, ok: trackedOk,
action: 'track_entity', action: 'track_entity',
layerId: family.layerId, layerId: family.layerId,
kind: family.kind, kind: family.kind,
// Aircraft follow the flight layers' label convention (callsign → // Aircraft follow the flight layers' label convention (callsign →
// registration → icao24) so the spoken name matches what the UI shows; // registration → icao24) so the spoken name matches what the UI shows;
// `registration` is absent on vessels/satellites and simply falls // `registration` is absent on vessels/satellites and simply falls
// through to their own name/id links. // through to their own name/id links.
label: formatTrackedEntityLabel(found, query), label: formatTrackedEntityLabel(found, query),
latitude: found.latitude ?? null, latitude: found.latitude ?? null,
longitude: found.longitude ?? null, longitude: found.longitude ?? null,
altitudeM: Number.isFinite(found.altitudeM) altitudeM: Number.isFinite(found.altitudeM)
? Math.round(found.altitudeM) ? Math.round(found.altitudeM)
: null, : null,
error: trackedOk ? null : 'Match found but tracking failed', error: trackedOk ? null : 'Match found but tracking failed',
}; };
}, },
); );
} }
@@ -2337,40 +2341,40 @@ async function frameOverhead(viewer, dataManager, styleManager, args = {}) {
'frame', 'frame',
'frame_overhead', 'frame_overhead',
() => { () => {
viewer.camera.flyToBoundingSphere(sphere, { viewer.camera.flyToBoundingSphere(sphere, {
duration: 2.0, duration: 2.0,
offset: new Cesium.HeadingPitchRange( offset: new Cesium.HeadingPitchRange(
viewer.camera.heading, viewer.camera.heading,
pitch, pitch,
sphere.radius * 2.4, sphere.radius * 2.4,
), ),
}); });
let detectionEnabled = false; let detectionEnabled = false;
try { try {
const detectionState = styleManager?.getDetectionState?.(); const detectionState = styleManager?.getDetectionState?.();
if (detectionState?.detectionMode === 'OFF') { if (detectionState?.detectionMode === 'OFF') {
const detectionResult = styleManager.setDetection({ mode: 'dense' }); const detectionResult = styleManager.setDetection({ mode: 'dense' });
detectionEnabled = detectionResult?.ok === true; detectionEnabled = detectionResult?.ok === true;
} else if (detectionState) { } else if (detectionState) {
detectionEnabled = true; detectionEnabled = true;
}
} catch {
// detection facade unavailable; framing still succeeded
} }
} catch {
// detection facade unavailable; framing still succeeded
}
return { return {
ok: true, ok: true,
action: 'frame_overhead', action: 'frame_overhead',
layerId, layerId,
radiusKm: Math.round(radiusKm), radiusKm: Math.round(radiusKm),
count: entries.length, count: entries.length,
detectionEnabled, detectionEnabled,
nearest: entries.slice(0, 5).map((entry) => ({ nearest: entries.slice(0, 5).map((entry) => ({
id: entry.id || entry.icao24 || entry.mmsi || null, id: entry.id || entry.icao24 || entry.mmsi || null,
label: entry.label || entry.callsign || entry.name || null, label: entry.label || entry.callsign || entry.name || null,
})), })),
}; };
}, },
); );
} }
@@ -2491,8 +2495,8 @@ export async function getBasemapLabelContext(
]).slice(0, 16), ]).slice(0, 16),
nearbyPlaceLabels: uniqueStrings( nearbyPlaceLabels: uniqueStrings(
(nearbyPlaces || []).flatMap((nearbyPlace) => [ (nearbyPlaces || []).flatMap((nearbyPlace) => [
nearbyPlace.name, nearbyPlace.name,
nearbyPlace.address, nearbyPlace.address,
]), ]),
).slice(0, 24), ).slice(0, 24),
}; };
@@ -2661,7 +2665,8 @@ function nextIssPass(viewer, dataManager, args) {
peakElevationDeg: Math.round(pass.maxElevDeg), peakElevationDeg: Math.round(pass.maxElevDeg),
riseDirection: compassDir(pass.riseAzDeg), riseDirection: compassDir(pass.riseAzDeg),
visible: typeof pass.visible === 'boolean' ? pass.visible : null, visible: typeof pass.visible === 'boolean' ? pass.visible : null,
visibilityNote: 'Geometric illumination estimate only; weather, brightness and orbital-element age affect actual visibility.', visibilityNote:
'Geometric illumination estimate only; weather, brightness and orbital-element age affect actual visibility.',
setIso: new Date(pass.setMs).toISOString(), setIso: new Date(pass.setMs).toISOString(),
peakIso: new Date(pass.maxElevMs).toISOString(), peakIso: new Date(pass.maxElevMs).toISOString(),
}; };
@@ -2669,22 +2674,55 @@ function nextIssPass(viewer, dataManager, args) {
function nextSatellitePass(viewer, dataManager, args) { function nextSatellitePass(viewer, dataManager, args) {
const layer = dataManager?.layers?.get('satellites')?.module; const layer = dataManager?.layers?.get('satellites')?.module;
const identity = layer?.resolveSatelliteForPass?.(args.target) || { status: 'not-found' }; const identity = layer?.resolveSatelliteForPass?.(args.target) || {
if (identity.status !== 'ok') return { status: 'not-found',
ok: false, action: 'next_satellite_pass', ...identity,
error: identity.status === 'ambiguous' ? 'Several loaded satellites match. Choose a NORAD ID from candidates.' : 'No loaded satellite matches. Enable satellites and use an exact name or NORAD ID.',
}; };
if (identity.status !== 'ok')
return {
ok: false,
action: 'next_satellite_pass',
...identity,
error:
identity.status === 'ambiguous'
? 'Several loaded satellites match. Choose a NORAD ID from candidates.'
: 'No loaded satellite matches. Enable satellites and use an exact name or NORAD ID.',
};
// Reuse the legacy location fallback and result formatting, substituting only // Reuse the legacy location fallback and result formatting, substituting only
// this explicitly resolved catalog identity and the optional visibility filter. // this explicitly resolved catalog identity and the optional visibility filter.
const adapter = { layers: new Map([['satellites', { module: { const adapter = {
getNextIssPass: (options) => layer.getNextSatellitePass(identity.noradId, { ...options, requireVisible: args.visibleOnly === true }), layers: new Map([
} }]]) }; [
'satellites',
{
module: {
getNextIssPass: (options) =>
layer.getNextSatellitePass(identity.noradId, {
...options,
requireVisible: args.visibleOnly === true,
}),
},
},
],
]),
};
const result = nextIssPass(viewer, adapter, args); const result = nextIssPass(viewer, adapter, args);
if (result.error) { if (result.error) {
result.error = result.error.replace(/ISS/g, identity.name || String(identity.noradId)); result.error = result.error.replace(
if (args.visibleOnly === true) result.error += ' Search required estimated illumination under a dark sky.'; /ISS/g,
identity.name || String(identity.noradId),
);
if (args.visibleOnly === true)
result.error +=
' Search required estimated illumination under a dark sky.';
} }
return { ...result, action: 'next_satellite_pass', noradId: identity.noradId, name: identity.name, visibleOnly: args.visibleOnly === true, horizonHours: 24 }; return {
...result,
action: 'next_satellite_pass',
noradId: identity.noradId,
name: identity.name,
visibleOnly: args.visibleOnly === true,
horizonHours: 24,
};
} }
function normalizePanelId(value) { function normalizePanelId(value) {
@@ -2716,21 +2754,21 @@ function normalizeCockpitNavigationHints(rawAction) {
const targetLayer = const targetLayer =
raw.includes('vessel') || raw.includes('ship') || raw.includes('ais') raw.includes('vessel') || raw.includes('ship') || raw.includes('ais')
? 'ais-live-vessels' ? 'ais-live-vessels'
: raw.includes('installation') || : raw.includes('installation') ||
raw.includes('facility') || raw.includes('facility') ||
raw.includes('base') raw.includes('base')
? 'military-installations' ? 'military-installations'
: raw.includes('military') : raw.includes('military')
? 'military' ? 'military'
: null; : null;
const aircraftClass = const aircraftClass =
raw.includes('helicopter') || raw.includes('helicopter') ||
raw.includes('helo') || raw.includes('helo') ||
raw.includes('chopper') raw.includes('chopper')
? 'helicopter' ? 'helicopter'
: null; : null;
return { return {
targetLayer, targetLayer,
@@ -2839,10 +2877,10 @@ async function flyToRequestedLocation(
placeSearch = unavailablePlaceSearch, placeSearch = unavailablePlaceSearch,
searchNavigation = searchAndFlyTo, searchNavigation = searchAndFlyTo,
signal, signal,
onStart = null, onStart = null,
runImmediate = null, runImmediate = null,
beginDeferred = null, beginDeferred = null,
reassertDeferred = null, reassertDeferred = null,
} = {}, } = {},
) { ) {
const requestedRangeM = Number(args.rangeM); const requestedRangeM = Number(args.rangeM);
@@ -2865,11 +2903,11 @@ async function flyToRequestedLocation(
? new Promise((resolve) => { ? new Promise((resolve) => {
settleArrival = resolve; settleArrival = resolve;
}) })
: null; : null;
const arrivalHooks = arrival const arrivalHooks = arrival
? { ? {
onComplete: () => settleArrival?.('arrived'), onComplete: () => settleArrival?.('arrived'),
onCancel: () => settleArrival?.('cancelled'), onCancel: () => settleArrival?.('cancelled'),
} }
: {}; : {};
const afterArrival = async (result, label) => { const afterArrival = async (result, label) => {
@@ -2884,12 +2922,12 @@ async function flyToRequestedLocation(
if (locationId) { if (locationId) {
const result = immediate(() => const result = immediate(() =>
flyToPresetLocation(viewer, locationId, { flyToPresetLocation(viewer, locationId, {
...(rangeM || args.viewMode === 'close' ...(rangeM || args.viewMode === 'close'
? { range: rangeM || 250 } ? { range: rangeM || 250 }
: { viewMode: 'overview' }), : { viewMode: 'overview' }),
duration: 2.2, duration: 2.2,
onStart: immediateOnStart, onStart: immediateOnStart,
...arrivalHooks, ...arrivalHooks,
}), }),
); );
if (result === false) if (result === false)
@@ -2914,13 +2952,13 @@ async function flyToRequestedLocation(
if (Number.isFinite(latitude) && Number.isFinite(longitude)) { if (Number.isFinite(latitude) && Number.isFinite(longitude)) {
const result = immediate(() => const result = immediate(() =>
flyToLandmark(viewer, latitude, longitude, { flyToLandmark(viewer, latitude, longitude, {
range: rangeM || 250, range: rangeM || 250,
pitch: -35, pitch: -35,
heading: 0, heading: 0,
buildingHeight: 0, buildingHeight: 0,
duration: 2.2, duration: 2.2,
onStart: immediateOnStart, onStart: immediateOnStart,
...arrivalHooks, ...arrivalHooks,
}), }),
); );
if (result === false) if (result === false)
@@ -2946,10 +2984,10 @@ async function flyToRequestedLocation(
if (poiMatch) { if (poiMatch) {
const result = immediate(() => const result = immediate(() =>
flyToPOI(viewer, poiMatch.cityId, poiMatch.index, { flyToPOI(viewer, poiMatch.cityId, poiMatch.index, {
duration: 2.2, duration: 2.2,
onStart: immediateOnStart, onStart: immediateOnStart,
...arrivalHooks, ...arrivalHooks,
...(rangeM ? { range: rangeM } : {}), ...(rangeM ? { range: rangeM } : {}),
}), }),
); );
const poi = CITY_POIS[poiMatch.cityId]?.pois?.[poiMatch.index]; const poi = CITY_POIS[poiMatch.cityId]?.pois?.[poiMatch.index];
@@ -3029,19 +3067,19 @@ function getCurrentViewState(
style: styleManager.activeStyle || 'normal', style: styleManager.activeStyle || 'normal',
context: context:
typeof styleManager.getContextModeState === 'function' typeof styleManager.getContextModeState === 'function'
? { ? {
...withContextModeVocabulary(styleManager.getContextModeState()), ...withContextModeVocabulary(styleManager.getContextModeState()),
// The numbers on the operator's Contacts panel, so a window/count // The numbers on the operator's Contacts panel, so a window/count
// question can be answered from what they are looking at. // question can be answered from what they are looking at.
...(activeContactsWindow(dataManager) ...(activeContactsWindow(dataManager)
? { contactsWindow: activeContactsWindow(dataManager) } ? { contactsWindow: activeContactsWindow(dataManager) }
: {}), : {}),
} }
: null, : null,
cockpit: cockpit:
typeof styleManager.getCockpitState === 'function' typeof styleManager.getCockpitState === 'function'
? styleManager.getCockpitState() ? styleManager.getCockpitState()
: null, : null,
controls: controls:
typeof styleManager.getControlState === 'function' typeof styleManager.getControlState === 'function'
? styleManager.getControlState() ? styleManager.getControlState()
@@ -3058,7 +3096,9 @@ function getCurrentViewState(
source: layerSnapshot(layer).source, source: layerSnapshot(layer).source,
lastUpdate: layerSnapshot(layer).lastUpdate, lastUpdate: layerSnapshot(layer).lastUpdate,
})), })),
feedProvenance: feedProvenanceEnvelope(layerSnapshots(dataManager.getAll()).filter((layer) => layer.enabled)), feedProvenance: feedProvenanceEnvelope(
layerSnapshots(dataManager.getAll()).filter((layer) => layer.enabled),
),
}; };
} }
@@ -3092,7 +3132,7 @@ async function getEntityContext(
limit, limit,
target: viewTarget, target: viewTarget,
}) })
: []; : [];
const scene = await scenePromise; const scene = await scenePromise;
if ((scope === 'selected' || scope === 'auto') && selected) { if ((scope === 'selected' || scope === 'auto') && selected) {
@@ -3178,14 +3218,14 @@ function aircraftProximityWindowForQuery(dataManager, args, result) {
items: items items: items
.slice(0, Math.round(clampNumber(args.limit, 1, 50, 12))) .slice(0, Math.round(clampNumber(args.limit, 1, 50, 12)))
.map((item) => ({ .map((item) => ({
layerKey: item.layerKey, layerKey: item.layerKey,
id: item.id, id: item.id,
...(item.icao24 ? { icao24: item.icao24 } : {}), ...(item.icao24 ? { icao24: item.icao24 } : {}),
...(item.callsign ? { callsign: item.callsign } : {}), ...(item.callsign ? { callsign: item.callsign } : {}),
...(Number.isFinite(item.distance) ...(Number.isFinite(item.distance)
? { distanceKm: Math.round(item.distance / 100) / 10 } ? { distanceKm: Math.round(item.distance / 100) / 10 }
: {}), : {}),
})), })),
summary: { count }, summary: { count },
coverage: { coverage: {
layersQueried: result?.coverage?.layersQueried || [], layersQueried: result?.coverage?.layersQueried || [],
@@ -3283,15 +3323,15 @@ function visibleEntityContexts(
insertNearestRecord( insertNearestRecord(
nearbyRecords, nearbyRecords,
{ {
record, record,
distanceScore: target distanceScore: target
? approximateCoordinateDistanceSq( ? approximateCoordinateDistanceSq(
targetLat, targetLat,
targetLon, targetLon,
record.latitude, record.latitude,
record.longitude, record.longitude,
) )
: 0, : 0,
}, },
VISIBLE_ENTITY_SHORTLIST, VISIBLE_ENTITY_SHORTLIST,
); );
@@ -3448,16 +3488,16 @@ async function getBasemapContext(
const cachedNearbyPlaces = const cachedNearbyPlaces =
shouldFetchNearbyPlaces(cameraHeightM) && shouldFetchNearbyPlaces(cameraHeightM) &&
nearbyPlacesCache.has(nearbyCacheKey) nearbyPlacesCache.has(nearbyCacheKey)
? nearbyPlacesCache.get(nearbyCacheKey) ? nearbyPlacesCache.get(nearbyCacheKey)
: null; : null;
const placePromise = const placePromise =
shouldReverseGeocode(cameraHeightM) && !cachedPlace shouldReverseGeocode(cameraHeightM) && !cachedPlace
? reverseGeocode(latitude, longitude, service) ? reverseGeocode(latitude, longitude, service)
: Promise.resolve(cachedPlace); : Promise.resolve(cachedPlace);
const nearbyPlacesPromise = const nearbyPlacesPromise =
shouldFetchNearbyPlaces(cameraHeightM) && !cachedNearbyPlaces shouldFetchNearbyPlaces(cameraHeightM) && !cachedNearbyPlaces
? fetchNearbyPlaces(latitude, longitude, cameraHeightM, service) ? fetchNearbyPlaces(latitude, longitude, cameraHeightM, service)
: Promise.resolve(cachedNearbyPlaces); : Promise.resolve(cachedNearbyPlaces);
const [viewportPlaces, resolvedPlace, resolvedNearbyPlaces] = const [viewportPlaces, resolvedPlace, resolvedNearbyPlaces] =
await Promise.all([ await Promise.all([
resolveWithin( resolveWithin(
@@ -3465,13 +3505,13 @@ async function getBasemapContext(
BASEMAP_CONTEXT_WAIT_MS, BASEMAP_CONTEXT_WAIT_MS,
cachedViewportPlaces, cachedViewportPlaces,
), ),
resolveWithin(placePromise, BASEMAP_CONTEXT_WAIT_MS, cachedPlace), resolveWithin(placePromise, BASEMAP_CONTEXT_WAIT_MS, cachedPlace),
resolveWithin( resolveWithin(
nearbyPlacesPromise, nearbyPlacesPromise,
BASEMAP_CONTEXT_WAIT_MS, BASEMAP_CONTEXT_WAIT_MS,
cachedNearbyPlaces, cachedNearbyPlaces,
), ),
]); ]);
const place = resolvedPlace || fallbackPlace; const place = resolvedPlace || fallbackPlace;
const nearbyPlaces = resolvedNearbyPlaces || []; const nearbyPlaces = resolvedNearbyPlaces || [];
return { return {
@@ -3516,12 +3556,12 @@ function nearbyKnownLandmarks(latitude, longitude, cameraHeightM) {
if (!Number.isFinite(latitude) || !Number.isFinite(longitude)) return []; if (!Number.isFinite(latitude) || !Number.isFinite(longitude)) return [];
const maxDistanceKm = const maxDistanceKm =
cameraHeightM <= 5000 cameraHeightM <= 5000
? 2 ? 2
: cameraHeightM <= 50000 : cameraHeightM <= 50000
? 10 ? 10
: cameraHeightM <= 250000 : cameraHeightM <= 250000
? 35 ? 35
: 0; : 0;
if (maxDistanceKm <= 0) return []; if (maxDistanceKm <= 0) return [];
const matches = []; const matches = [];
@@ -3752,9 +3792,9 @@ function inferCountry(latitude, longitude) {
]; ];
const region = regions.find( const region = regions.find(
(item) => (item) =>
latitude >= item.south && latitude >= item.south &&
latitude <= item.north && latitude <= item.north &&
longitude >= item.west && longitude >= item.west &&
longitude <= item.east, longitude <= item.east,
); );
return region?.name || null; return region?.name || null;
@@ -3802,18 +3842,18 @@ async function reverseGeocodeViewportSamples(samples, cameraHeightM, service) {
sample.longitude, sample.longitude,
service, service,
); );
if (!place) return null; if (!place) return null;
return { return {
latitude: sample.latitude, latitude: sample.latitude,
longitude: sample.longitude, longitude: sample.longitude,
formattedAddress: place.formattedAddress, formattedAddress: place.formattedAddress,
locality: place.locality, locality: place.locality,
region: place.region, region: place.region,
country: place.country, country: place.country,
types: place.types, types: place.types,
labels: place.labels, labels: place.labels,
streetLabels: place.streetLabels, streetLabels: place.streetLabels,
}; };
}), }),
) )
).filter(Boolean); ).filter(Boolean);
@@ -3834,21 +3874,21 @@ function viewportPlacesFromCache(samples, cameraHeightM, service) {
const place = reverseGeocodeCache.get( const place = reverseGeocodeCache.get(
reverseGeocodeKey(sample.latitude, sample.longitude, service), reverseGeocodeKey(sample.latitude, sample.longitude, service),
); );
if (!place) return []; if (!place) return [];
return [ return [
{ {
latitude: sample.latitude, latitude: sample.latitude,
longitude: sample.longitude, longitude: sample.longitude,
formattedAddress: place.formattedAddress, formattedAddress: place.formattedAddress,
locality: place.locality, locality: place.locality,
region: place.region, region: place.region,
country: place.country, country: place.country,
types: place.types, types: place.types,
labels: place.labels, labels: place.labels,
streetLabels: place.streetLabels, streetLabels: place.streetLabels,
}, },
]; ];
}); });
return summarizeViewportPlaces(places); return summarizeViewportPlaces(places);
} }
@@ -4008,12 +4048,12 @@ function summarizeEntity(viewer, entity, { includeProperties = false } = {}) {
const tags = props.tags || {}; const tags = props.tags || {};
const label = cleanText( const label = cleanText(
props.name || props.name ||
tags.name || tags.name ||
tags['name:en'] || tags['name:en'] ||
tags.official_name || tags.official_name ||
tags.operator || tags.operator ||
props.operator || props.operator ||
entity.name || entity.name ||
layerTitle(layerId), layerTitle(layerId),
); );
const position = const position =
@@ -4073,8 +4113,8 @@ function unwrapProperties(value) {
for (const [key, entry] of Object.entries(value)) { for (const [key, entry] of Object.entries(value)) {
out[key] = out[key] =
entry && typeof entry.getValue === 'function' entry && typeof entry.getValue === 'function'
? unwrapProperties(entry.getValue(Cesium.JulianDate.now())) ? unwrapProperties(entry.getValue(Cesium.JulianDate.now()))
: unwrapProperties(entry); : unwrapProperties(entry);
} }
return out; return out;
} }
@@ -4189,10 +4229,15 @@ function analystProviders(
const row = dataManager.getAll?.().find((layer) => layer.id === layerKey); const row = dataManager.getAll?.().find((layer) => layer.id === layerKey);
if (row) return layerSnapshot(row); if (row) return layerSnapshot(row);
const module = dataManager.layers?.get(layerKey)?.module; const module = dataManager.layers?.get(layerKey)?.module;
return layerSnapshot({ id: layerKey, enabled: dataManager.isEnabled?.(layerKey), stats: module?.getStats?.() || {} }); return layerSnapshot({
id: layerKey,
enabled: dataManager.isEnabled?.(layerKey),
stats: module?.getStats?.() || {},
});
}, },
getRecordCoverage(layerKey, rows) { getRecordCoverage(layerKey, rows) {
if (!['satellites', 'local-datacenters', 'local-dams'].includes(layerKey)) return null; if (!['satellites', 'local-datacenters', 'local-dams'].includes(layerKey))
return null;
const module = dataManager.layers.get(layerKey)?.module; const module = dataManager.layers.get(layerKey)?.module;
const loaded = module?.getStats?.().count; const loaded = module?.getStats?.().count;
return { return {
@@ -4271,7 +4316,36 @@ async function runAnalystQuery(
// model burned the turn on retries (owner field session 2026-08-21, 23:48). // model burned the turn on retries (owner field session 2026-08-21, 23:48).
const items = result.items.map((r) => { const items = result.items.map((r) => {
const compact = { layerKey: r.layerKey, id: r.id }; const compact = { layerKey: r.layerKey, id: r.id };
for (const k of ['icao24', 'mmsi', 'registration', 'label', 'callsign', 'name', 'altitudeM', 'speedMps', 'speedKts', 'frp', 'magnitude', 'shipType', 'destination', 'operator', 'routeOrigin', 'routeDestination', 'aircraftClass', 'military', 'onGround', 'distanceKm', 'confidence', 'place', 'noradId', 'satelliteClass', 'group', 'river', 'output', 'capacity']) { for (const k of [
'icao24',
'mmsi',
'registration',
'label',
'callsign',
'name',
'altitudeM',
'speedMps',
'speedKts',
'frp',
'magnitude',
'shipType',
'destination',
'operator',
'routeOrigin',
'routeDestination',
'aircraftClass',
'military',
'onGround',
'distanceKm',
'confidence',
'place',
'noradId',
'satelliteClass',
'group',
'river',
'output',
'capacity',
]) {
if (r[k] !== null && r[k] !== undefined) compact[k] = r[k]; if (r[k] !== null && r[k] !== undefined) compact[k] = r[k];
} }
return compact; return compact;
@@ -4305,10 +4379,22 @@ async function runAnalystQuery(
// differ. The generic record/scope engine still owns explicit regions and // differ. The generic record/scope engine still owns explicit regions and
// arbitrary points — only "how many aircraft around <this contact>" is // arbitrary points — only "how many aircraft around <this contact>" is
// unified, because that is the question the panel is already answering. // unified, because that is the question the panel is already answering.
const entityWindow = aircraftProximityWindowForQuery(dataManager, args, result); const entityWindow = aircraftProximityWindowForQuery(
dataManager,
args,
result,
);
if (entityWindow) { if (entityWindow) {
const provenance = feedProvenanceEnvelope(layerSnapshots(dataManager.getAll?.() || []).filter((layer) => layer.enabled && ['flights', 'military'].includes(layer.id))); const provenance = feedProvenanceEnvelope(
return { ...entityWindow, feedProvenance: provenance, feedState: provenance.overall }; layerSnapshots(dataManager.getAll?.() || []).filter(
(layer) => layer.enabled && ['flights', 'military'].includes(layer.id),
),
);
return {
...entityWindow,
feedProvenance: provenance,
feedState: provenance.overall,
};
} }
const contactsWindow = activeContactsWindow(dataManager); const contactsWindow = activeContactsWindow(dataManager);
@@ -4336,7 +4422,7 @@ async function runAnalystQuery(
`${contactsWindow.radiusKm} km of ${contactsWindow.centeredOn}, and that is the answer to a bare ` + `${contactsWindow.radiusKm} km of ${contactsWindow.centeredOn}, and that is the answer to a bare ` +
`"how many aircraft are nearby". This query measured something else — ${result.count} ${result.scopeLabel}. ` + `"how many aircraft are nearby". This query measured something else — ${result.count} ${result.scopeLabel}. ` +
'Give this one only if the operator asked about that specific area, and name both scopes if you give both.' 'Give this one only if the operator asked about that specific area, and name both scopes if you give both.'
: null; : null;
return { return {
ok: true, ok: true,
action: 'analyst_query', action: 'analyst_query',
@@ -4356,10 +4442,10 @@ async function runAnalystQuery(
// missed inside a nested shape. // missed inside a nested shape.
...(contactsWindow && aircraftQueried ...(contactsWindow && aircraftQueried
? { ? {
contactsWindow, contactsWindow,
contactsWindowCount: windowAircraft, contactsWindowCount: windowAircraft,
contactsWindowSubject: contactsWindow.centeredOn || null, contactsWindowSubject: contactsWindow.centeredOn || null,
} }
: {}), : {}),
...(countsReconciliation ? { countsReconciliation } : {}), ...(countsReconciliation ? { countsReconciliation } : {}),
}; };