@butlr/butlr-mcp-server 0.5.1 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/README.md +1 -1
  2. package/dist/cache/topology-cache.d.ts +6 -6
  3. package/dist/cache/topology-cache.js +6 -6
  4. package/dist/clients/queries/topology.d.ts +14 -0
  5. package/dist/clients/queries/topology.d.ts.map +1 -1
  6. package/dist/clients/queries/topology.js +48 -0
  7. package/dist/clients/queries/topology.js.map +1 -1
  8. package/dist/clients/reporting-client.d.ts +6 -0
  9. package/dist/clients/reporting-client.d.ts.map +1 -1
  10. package/dist/clients/reporting-client.js.map +1 -1
  11. package/dist/clients/types.d.ts +1 -1
  12. package/dist/clients/types.d.ts.map +1 -1
  13. package/dist/tools/butlr-list-topology.d.ts.map +1 -1
  14. package/dist/tools/butlr-list-topology.js +7 -53
  15. package/dist/tools/butlr-list-topology.js.map +1 -1
  16. package/dist/tools/butlr-search-assets.d.ts +1 -0
  17. package/dist/tools/butlr-search-assets.d.ts.map +1 -1
  18. package/dist/tools/butlr-search-assets.js +59 -15
  19. package/dist/tools/butlr-search-assets.js.map +1 -1
  20. package/dist/tools/butlr-traffic-flow.d.ts.map +1 -1
  21. package/dist/tools/butlr-traffic-flow.js +147 -54
  22. package/dist/tools/butlr-traffic-flow.js.map +1 -1
  23. package/dist/types/responses.d.ts +1 -1
  24. package/dist/types/responses.d.ts.map +1 -1
  25. package/dist/utils/asset-flattener.d.ts.map +1 -1
  26. package/dist/utils/asset-flattener.js +15 -3
  27. package/dist/utils/asset-flattener.js.map +1 -1
  28. package/dist/utils/graphql-helpers.d.ts +26 -1
  29. package/dist/utils/graphql-helpers.d.ts.map +1 -1
  30. package/dist/utils/graphql-helpers.js +30 -5
  31. package/dist/utils/graphql-helpers.js.map +1 -1
  32. package/dist/utils/occupancy-helpers.d.ts +72 -3
  33. package/dist/utils/occupancy-helpers.d.ts.map +1 -1
  34. package/dist/utils/occupancy-helpers.js +129 -18
  35. package/dist/utils/occupancy-helpers.js.map +1 -1
  36. package/dist/utils/topology-merge.d.ts +24 -0
  37. package/dist/utils/topology-merge.d.ts.map +1 -0
  38. package/dist/utils/topology-merge.js +57 -0
  39. package/dist/utils/topology-merge.js.map +1 -0
  40. package/llms.txt +1 -1
  41. package/package.json +1 -1
@@ -78,12 +78,18 @@ export function flattenTopology(sites) {
78
78
  building_name: building.name,
79
79
  floor_id: floor.id,
80
80
  floor_name: floor.name,
81
- room_id: zone.roomID,
81
+ room_id: zone.room_id || zone.roomID,
82
+ room_name: (floor.rooms || []).find((r) => r.id === (zone.room_id || zone.roomID))
83
+ ?.name,
82
84
  customID: zone.customID,
83
85
  capacity: zone.capacity,
84
86
  coordinates: zone.coordinates,
85
87
  });
86
88
  }
89
+ // Room names for device breadcrumbs. `buildAssetPath` renders a
90
+ // `room_name` segment for sensors, hives and zones, and the flat
91
+ // device lists carry only `room_id`.
92
+ const roomNamesById = new Map((floor.rooms || []).map((r) => [r.id, r.name]));
87
93
  // Add sensors
88
94
  for (const sensor of floor.sensors || []) {
89
95
  flattened.push({
@@ -96,7 +102,12 @@ export function flattenTopology(sites) {
96
102
  building_name: building.name,
97
103
  floor_id: floor.id,
98
104
  floor_name: floor.name,
99
- room_id: sensor.roomID,
105
+ // snake_case first: GET_ALL_SENSORS selects `room_id`, and the
106
+ // camelCase resolver is buggy for NULL values. Reading only
107
+ // `roomID` here dropped the room segment from every flattened
108
+ // sensor's breadcrumb path.
109
+ room_id: sensor.room_id || sensor.roomID,
110
+ room_name: roomNamesById.get(sensor.room_id || sensor.roomID || ""),
100
111
  mac_address: sensor.mac_address,
101
112
  mode: sensor.mode,
102
113
  model: sensor.model,
@@ -116,7 +127,8 @@ export function flattenTopology(sites) {
116
127
  building_name: building.name,
117
128
  floor_id: floor.id,
118
129
  floor_name: floor.name,
119
- room_id: hive.roomID,
130
+ room_id: hive.room_id || hive.roomID,
131
+ room_name: roomNamesById.get(hive.room_id || hive.roomID || ""),
120
132
  serialNumber: hive.serialNumber,
121
133
  is_online: hive.isOnline || hive.is_online,
122
134
  hiveVersion: hive.hiveVersion,
@@ -1 +1 @@
1
- {"version":3,"file":"asset-flattener.js","sourceRoot":"","sources":["../../src/utils/asset-flattener.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"asset-flattener.js","sourceRoot":"","sources":["../../src/utils/asset-flattener.ts"],"names":[],"mappings":"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"}
@@ -29,9 +29,34 @@ export declare function rethrowIfGraphQLError(error: unknown): void;
29
29
  export declare function throwIfGraphQLErrors(result: {
30
30
  error?: unknown;
31
31
  }): void;
32
+ /**
33
+ * Check if a sensor is a KNOWN test device: a mirror/virtual sensor
34
+ * (mi-rr-or*) or a fake test sensor (fa-ke*).
35
+ *
36
+ * Use this when refusing a caller's explicit request for one named sensor.
37
+ * Refusing costs the caller their query, so it needs positive evidence, and
38
+ * the MAC prefixes are the only positive evidence available. A blank or
39
+ * missing `mac_address` is unknown provenance, not proof: a provisioned but
40
+ * not yet MAC bound sensor is a real device with real reporting rows, and
41
+ * sensors are addressed by `id` everywhere, so a blank MAC never makes a row
42
+ * unqueryable.
43
+ *
44
+ * `isProductionSensor` below is the stricter counterpart for FILTERING
45
+ * aggregate lists, where the trade runs the other way.
46
+ */
47
+ export declare function isKnownTestSensor(sensor: Sensor): boolean;
32
48
  /**
33
49
  * Check if a sensor is a production device (not a test/placeholder).
34
- * Filters out mirror/virtual sensors (mi-rr-or*) and fake test sensors (fa-ke*).
50
+ * Filters out mirror/virtual sensors (mi-rr-or*), fake test sensors (fa-ke*),
51
+ * and MAC-less placeholder rows.
52
+ *
53
+ * Stricter than `isKnownTestSensor` on purpose. This is the filter for
54
+ * aggregate views (topology listings, hardware health, occupancy sensor
55
+ * counts), where a MAC-less placeholder row inflates every headline number it
56
+ * lands in, and `butlr_hardware_snapshot` reports those rows under
57
+ * `test_devices_excluded.sensors.placeholder`. Excluding an unknown row from a
58
+ * total is cheap; refusing a caller's explicit query for it is not, which is
59
+ * why the single-sensor path uses `isKnownTestSensor` instead.
35
60
  */
36
61
  export declare function isProductionSensor(sensor: Sensor): boolean;
37
62
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"graphql-helpers.d.ts","sourceRoot":"","sources":["../../src/utils/graphql-helpers.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,qBAAqB,CAAC;AAGxD;;;;;;;;;GASG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAK1D;AAED;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,IAAI,CActE;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAO1D;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAMpD"}
1
+ {"version":3,"file":"graphql-helpers.d.ts","sourceRoot":"","sources":["../../src/utils/graphql-helpers.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,qBAAqB,CAAC;AAGxD;;;;;;;;;GASG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAK1D;AAED;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,IAAI,CActE;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAGzD;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAE1D;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAMpD"}
@@ -46,15 +46,40 @@ export function throwIfGraphQLErrors(result) {
46
46
  // Surface other ErrorLike shapes (e.g. ServerError) for the outer catch.
47
47
  throw result.error;
48
48
  }
49
+ /**
50
+ * Check if a sensor is a KNOWN test device: a mirror/virtual sensor
51
+ * (mi-rr-or*) or a fake test sensor (fa-ke*).
52
+ *
53
+ * Use this when refusing a caller's explicit request for one named sensor.
54
+ * Refusing costs the caller their query, so it needs positive evidence, and
55
+ * the MAC prefixes are the only positive evidence available. A blank or
56
+ * missing `mac_address` is unknown provenance, not proof: a provisioned but
57
+ * not yet MAC bound sensor is a real device with real reporting rows, and
58
+ * sensors are addressed by `id` everywhere, so a blank MAC never makes a row
59
+ * unqueryable.
60
+ *
61
+ * `isProductionSensor` below is the stricter counterpart for FILTERING
62
+ * aggregate lists, where the trade runs the other way.
63
+ */
64
+ export function isKnownTestSensor(sensor) {
65
+ const mac = sensor.mac_address?.trim() ?? "";
66
+ return mac.startsWith("mi-rr-or") || mac.startsWith("fa-ke");
67
+ }
49
68
  /**
50
69
  * Check if a sensor is a production device (not a test/placeholder).
51
- * Filters out mirror/virtual sensors (mi-rr-or*) and fake test sensors (fa-ke*).
70
+ * Filters out mirror/virtual sensors (mi-rr-or*), fake test sensors (fa-ke*),
71
+ * and MAC-less placeholder rows.
72
+ *
73
+ * Stricter than `isKnownTestSensor` on purpose. This is the filter for
74
+ * aggregate views (topology listings, hardware health, occupancy sensor
75
+ * counts), where a MAC-less placeholder row inflates every headline number it
76
+ * lands in, and `butlr_hardware_snapshot` reports those rows under
77
+ * `test_devices_excluded.sensors.placeholder`. Excluding an unknown row from a
78
+ * total is cheap; refusing a caller's explicit query for it is not, which is
79
+ * why the single-sensor path uses `isKnownTestSensor` instead.
52
80
  */
53
81
  export function isProductionSensor(sensor) {
54
- return (!!sensor.mac_address &&
55
- sensor.mac_address.trim() !== "" &&
56
- !sensor.mac_address.startsWith("mi-rr-or") &&
57
- !sensor.mac_address.startsWith("fa-ke"));
82
+ return !!sensor.mac_address && sensor.mac_address.trim() !== "" && !isKnownTestSensor(sensor);
58
83
  }
59
84
  /**
60
85
  * Check if a hive is a production device (not a test/placeholder).
@@ -1 +1 @@
1
- {"version":3,"file":"graphql-helpers.js","sourceRoot":"","sources":["../../src/utils/graphql-helpers.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAE9D,OAAO,EAAE,qBAAqB,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAEhF;;;;;;;;;GASG;AACH,MAAM,UAAU,qBAAqB,CAAC,KAAc;IAClD,IAAI,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,eAAe,IAAI,KAAK,IAAI,cAAc,IAAI,KAAK,CAAC,EAAE,CAAC;QAChG,MAAM,QAAQ,GAAG,qBAAqB,CAAC,KAAoD,CAAC,CAAC;QAC7F,MAAM,IAAI,KAAK,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC,CAAC;IAC5C,CAAC;AACH,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,oBAAoB,CAAC,MAA2B;IAC9D,IAAI,CAAC,MAAM,CAAC,KAAK;QAAE,OAAO;IAE1B,IAAI,qBAAqB,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;QAC3C,qBAAqB,CAAC;YACpB,aAAa,EAAE,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;gBAC7C,OAAO,EAAE,CAAC,CAAC,OAAO;gBAClB,UAAU,EAAE,CAAC,CAAC,UAAU;aACzB,CAAC,CAAC;SACJ,CAAC,CAAC;IACL,CAAC;IAED,yEAAyE;IACzE,MAAM,MAAM,CAAC,KAAK,CAAC;AACrB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAAC,MAAc;IAC/C,OAAO,CACL,CAAC,CAAC,MAAM,CAAC,WAAW;QACpB,MAAM,CAAC,WAAW,CAAC,IAAI,EAAE,KAAK,EAAE;QAChC,CAAC,MAAM,CAAC,WAAW,CAAC,UAAU,CAAC,UAAU,CAAC;QAC1C,CAAC,MAAM,CAAC,WAAW,CAAC,UAAU,CAAC,OAAO,CAAC,CACxC,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAAU;IACzC,OAAO,CACL,CAAC,CAAC,IAAI,CAAC,YAAY;QACnB,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE,KAAK,EAAE;QAC/B,CAAC,IAAI,CAAC,YAAY,CAAC,WAAW,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC,CACpD,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"graphql-helpers.js","sourceRoot":"","sources":["../../src/utils/graphql-helpers.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAE9D,OAAO,EAAE,qBAAqB,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAEhF;;;;;;;;;GASG;AACH,MAAM,UAAU,qBAAqB,CAAC,KAAc;IAClD,IAAI,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,eAAe,IAAI,KAAK,IAAI,cAAc,IAAI,KAAK,CAAC,EAAE,CAAC;QAChG,MAAM,QAAQ,GAAG,qBAAqB,CAAC,KAAoD,CAAC,CAAC;QAC7F,MAAM,IAAI,KAAK,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC,CAAC;IAC5C,CAAC;AACH,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,oBAAoB,CAAC,MAA2B;IAC9D,IAAI,CAAC,MAAM,CAAC,KAAK;QAAE,OAAO;IAE1B,IAAI,qBAAqB,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;QAC3C,qBAAqB,CAAC;YACpB,aAAa,EAAE,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;gBAC7C,OAAO,EAAE,CAAC,CAAC,OAAO;gBAClB,UAAU,EAAE,CAAC,CAAC,UAAU;aACzB,CAAC,CAAC;SACJ,CAAC,CAAC;IACL,CAAC;IAED,yEAAyE;IACzE,MAAM,MAAM,CAAC,KAAK,CAAC;AACrB,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,iBAAiB,CAAC,MAAc;IAC9C,MAAM,GAAG,GAAG,MAAM,CAAC,WAAW,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IAC7C,OAAO,GAAG,CAAC,UAAU,CAAC,UAAU,CAAC,IAAI,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;AAC/D,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,kBAAkB,CAAC,MAAc;IAC/C,OAAO,CAAC,CAAC,MAAM,CAAC,WAAW,IAAI,MAAM,CAAC,WAAW,CAAC,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,iBAAiB,CAAC,MAAM,CAAC,CAAC;AAChG,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAAU;IACzC,OAAO,CACL,CAAC,CAAC,IAAI,CAAC,YAAY;QACnB,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE,KAAK,EAAE;QAC/B,CAAC,IAAI,CAAC,YAAY,CAAC,WAAW,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC,CACpD,CAAC;AACJ,CAAC"}
@@ -5,18 +5,52 @@
5
5
  * Both tools share: topology fetching, sensor filtering, asset resolution,
6
6
  * measurement selection, and recommendation logic.
7
7
  */
8
- import type { Sensor, Site, Floor, Building } from "../clients/types.js";
8
+ import type { Sensor, Site, Floor, Building, Room } from "../clients/types.js";
9
9
  import type { TimezoneMetadata } from "./timezone-helpers.js";
10
10
  import type { MeasurementRecommendation, BaseMeasurementData } from "../types/responses.js";
11
11
  /**
12
- * Topology and sensor data fetched in parallel for occupancy tools.
12
+ * The spatial hierarchy on its own, flattened for lookup.
13
+ *
14
+ * Split out from TopologyContext because a caller that resolves ONE known
15
+ * sensor needs the hierarchy but not the org's whole sensor inventory.
13
16
  */
14
- export interface TopologyContext {
17
+ export interface TopologyOnly {
15
18
  sites: Site[];
16
19
  buildings: Building[];
17
20
  floors: Floor[];
21
+ }
22
+ /**
23
+ * Topology and sensor data fetched in parallel for occupancy tools.
24
+ */
25
+ export interface TopologyContext extends TopologyOnly {
18
26
  productionSensors: Sensor[];
19
27
  }
28
+ /**
29
+ * Fetch and flatten the spatial hierarchy (sites, buildings, floors).
30
+ */
31
+ export declare function fetchTopology(): Promise<TopologyOnly>;
32
+ /**
33
+ * Fetch the org's full sensor inventory, test/mirror devices removed.
34
+ */
35
+ export declare function fetchProductionSensors(): Promise<Sensor[]>;
36
+ /**
37
+ * Fetch specific sensors by ID.
38
+ *
39
+ * Unlike fetchProductionSensors this does NOT filter test devices: the caller
40
+ * asked for these exact IDs, so a mirror device has to come back so the caller
41
+ * can say so, rather than silently becoming "not found".
42
+ */
43
+ export declare function fetchSensorsByIds(ids: string[]): Promise<Sensor[]>;
44
+ /**
45
+ * Fetch the sensors bound to specific rooms via `sensors(room_ids:)`.
46
+ *
47
+ * Like fetchSensorsByIds this does NOT filter test devices: the caller scoped
48
+ * the query to rooms it already knows about, and the row set has to be
49
+ * complete so the caller can apply whatever gate fits its use (e.g.
50
+ * isKnownTestSensor for a refusal gate that must not drop MAC-less
51
+ * placeholder rows).
52
+ */
53
+ export declare function fetchSensorsByRoomIds(roomIds: string[]): Promise<Sensor[]>;
20
54
  /**
21
55
  * Fetch topology and production sensors in a single parallel call.
22
56
  * Shared by both current-occupancy and timeseries tools.
@@ -39,6 +73,41 @@ export interface AssetContext {
39
73
  * Resolve full context for an asset ID: type validation, name, timezone, sensor partitioning.
40
74
  */
41
75
  export declare function resolveAssetContext(assetId: string, ctx: TopologyContext): AssetContext;
76
+ /**
77
+ * Resolved context for a single sensor: display name, timezone, and the
78
+ * breadcrumb path to it.
79
+ *
80
+ * Lives next to resolveAssetContext so there is ONE definition of how a
81
+ * sensor's timezone and path are derived. Sensors are not an asset type
82
+ * resolveAssetContext handles (it partitions an enclosing space's sensors by
83
+ * mode, which is not meaningful for a single device), but they resolve
84
+ * against the same topology by the same rules, and a second copy of those
85
+ * rules in a tool is how the two drifted apart before.
86
+ */
87
+ export interface SensorContext {
88
+ name: string;
89
+ timezone: string;
90
+ tzMetadata: TimezoneMetadata;
91
+ timezoneFallback: boolean;
92
+ path: string;
93
+ room?: Room;
94
+ floor?: Floor;
95
+ building?: Building;
96
+ }
97
+ /**
98
+ * Resolve a single sensor's display name, timezone and breadcrumb path.
99
+ *
100
+ * Room first, floor second, for BOTH timezone and path. The room's own floor
101
+ * is authoritative: `sensor.floor_id` can be unset while `room_id` still
102
+ * resolves, and it can disagree with the room's actual floor. Keying the path
103
+ * off `floor_id` (while keying the timezone off `room_id`) drops every path
104
+ * segment in the first case and names the wrong floor in the second.
105
+ *
106
+ * Only snake_case linkage fields are read. Both queries that feed this
107
+ * (GET_ALL_SENSORS, GET_SENSORS_BY_IDS) select `floor_id`/`room_id` and not
108
+ * the camelCase resolvers, which are buggy for NULL values.
109
+ */
110
+ export declare function resolveSensorContext(sensor: Sensor, ctx: TopologyOnly): SensorContext;
42
111
  /**
43
112
  * Get the measurement name for presence data based on asset type.
44
113
  */
@@ -1 +1 @@
1
- {"version":3,"file":"occupancy-helpers.d.ts","sourceRoot":"","sources":["../../src/utils/occupancy-helpers.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAQ,MAAM,qBAAqB,CAAC;AAC/E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,KAAK,EAAE,yBAAyB,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAM5F;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,SAAS,EAAE,QAAQ,EAAE,CAAC;IACtB,MAAM,EAAE,KAAK,EAAE,CAAC;IAChB,iBAAiB,EAAE,MAAM,EAAE,CAAC;CAC7B;AAED;;;GAGG;AACH,wBAAsB,uBAAuB,IAAI,OAAO,CAAC,eAAe,CAAC,CA4BxE;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,CAAC;IACrC,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,gBAAgB,CAAC;IAC7B,gBAAgB,EAAE,OAAO,CAAC;IAC1B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,cAAc,EAAE,MAAM,EAAE,CAAC;CAC1B;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,eAAe,GAAG,YAAY,CA8EvF;AAwCD;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,CASnF;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,CAOzE;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CACrC,SAAS,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,EACpC,WAAW,EAAE,MAAM,GAClB,MAAM,CASR;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CACpC,SAAS,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,EACpC,WAAW,EAAE,MAAM,GAClB,MAAM,CASR;AAED;;;;;;GAMG;AACH,MAAM,WAAW,qBAAqB;IACpC,SAAS,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,CAAC;IACrC,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,mBAAmB,EAC7B,OAAO,EAAE,mBAAmB,EAC5B,eAAe,EAAE,OAAO,EACxB,cAAc,EAAE,OAAO,EACvB,GAAG,EAAE,qBAAqB,GACzB,yBAAyB,CA4B3B"}
1
+ {"version":3,"file":"occupancy-helpers.d.ts","sourceRoot":"","sources":["../../src/utils/occupancy-helpers.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AASH,OAAO,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAQ,MAAM,qBAAqB,CAAC;AACrF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,KAAK,EAAE,yBAAyB,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAM5F;;;;;GAKG;AACH,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,SAAS,EAAE,QAAQ,EAAE,CAAC;IACtB,MAAM,EAAE,KAAK,EAAE,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,eAAgB,SAAQ,YAAY;IACnD,iBAAiB,EAAE,MAAM,EAAE,CAAC;CAC7B;AAED;;GAEG;AACH,wBAAsB,aAAa,IAAI,OAAO,CAAC,YAAY,CAAC,CAmB3D;AAED;;GAEG;AACH,wBAAsB,sBAAsB,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC,CAgBhE;AAED;;;;;;GAMG;AACH,wBAAsB,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAkBxE;AAED;;;;;;;;GAQG;AACH,wBAAsB,qBAAqB,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAkBhF;AAED;;;GAGG;AACH,wBAAsB,uBAAuB,IAAI,OAAO,CAAC,eAAe,CAAC,CAOxE;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,CAAC;IACrC,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,gBAAgB,CAAC;IAC7B,gBAAgB,EAAE,OAAO,CAAC;IAC1B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,cAAc,EAAE,MAAM,EAAE,CAAC;CAC1B;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,eAAe,GAAG,YAAY,CA8EvF;AAED;;;;;;;;;;GAUG;AACH,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,gBAAgB,CAAC;IAC7B,gBAAgB,EAAE,OAAO,CAAC;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,IAAI,CAAC;IACZ,KAAK,CAAC,EAAE,KAAK,CAAC;IACd,QAAQ,CAAC,EAAE,QAAQ,CAAC;CACrB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,YAAY,GAAG,aAAa,CA6BrF;AAwCD;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,CASnF;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,CAOzE;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CACrC,SAAS,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,EACpC,WAAW,EAAE,MAAM,GAClB,MAAM,CASR;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CACpC,SAAS,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,EACpC,WAAW,EAAE,MAAM,GAClB,MAAM,CASR;AAED;;;;;;GAMG;AACH,MAAM,WAAW,qBAAqB;IACpC,SAAS,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,CAAC;IACrC,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,mBAAmB,EAC7B,OAAO,EAAE,mBAAmB,EAC5B,eAAe,EAAE,OAAO,EACxB,cAAc,EAAE,OAAO,EACvB,GAAG,EAAE,qBAAqB,GACzB,yBAAyB,CA4B3B"}
@@ -6,30 +6,22 @@
6
6
  * measurement selection, and recommendation logic.
7
7
  */
8
8
  import { apolloClient } from "../clients/graphql-client.js";
9
- import { GET_ALL_SENSORS, GET_FULL_TOPOLOGY } from "../clients/queries/topology.js";
9
+ import { GET_ALL_SENSORS, GET_FULL_TOPOLOGY, GET_SENSORS_BY_IDS, GET_SENSORS_BY_ROOM_IDS, } from "../clients/queries/topology.js";
10
10
  import { detectAssetType } from "./asset-helpers.js";
11
11
  import { isProductionSensor, throwIfGraphQLErrors } from "./graphql-helpers.js";
12
12
  import { getTimezoneForAsset, buildTimezoneMetadata } from "./timezone-helpers.js";
13
13
  import { rethrowIfGraphQLError } from "./graphql-helpers.js";
14
14
  /**
15
- * Fetch topology and production sensors in a single parallel call.
16
- * Shared by both current-occupancy and timeseries tools.
15
+ * Fetch and flatten the spatial hierarchy (sites, buildings, floors).
17
16
  */
18
- export async function fetchTopologyAndSensors() {
19
- let topoResult, sensorsResult;
17
+ export async function fetchTopology() {
18
+ let topoResult;
20
19
  try {
21
- [topoResult, sensorsResult] = await Promise.all([
22
- apolloClient.query({
23
- query: GET_FULL_TOPOLOGY,
24
- fetchPolicy: "network-only",
25
- }),
26
- apolloClient.query({
27
- query: GET_ALL_SENSORS,
28
- fetchPolicy: "network-only",
29
- }),
30
- ]);
20
+ topoResult = await apolloClient.query({
21
+ query: GET_FULL_TOPOLOGY,
22
+ fetchPolicy: "network-only",
23
+ });
31
24
  throwIfGraphQLErrors(topoResult);
32
- throwIfGraphQLErrors(sensorsResult);
33
25
  }
34
26
  catch (error) {
35
27
  rethrowIfGraphQLError(error);
@@ -38,9 +30,89 @@ export async function fetchTopologyAndSensors() {
38
30
  const sites = topoResult.data?.sites?.data || [];
39
31
  const buildings = sites.flatMap((s) => s.buildings || []);
40
32
  const floors = buildings.flatMap((b) => b.floors || []);
33
+ return { sites, buildings, floors };
34
+ }
35
+ /**
36
+ * Fetch the org's full sensor inventory, test/mirror devices removed.
37
+ */
38
+ export async function fetchProductionSensors() {
39
+ let sensorsResult;
40
+ try {
41
+ sensorsResult = await apolloClient.query({
42
+ query: GET_ALL_SENSORS,
43
+ fetchPolicy: "network-only",
44
+ });
45
+ throwIfGraphQLErrors(sensorsResult);
46
+ }
47
+ catch (error) {
48
+ rethrowIfGraphQLError(error);
49
+ throw error;
50
+ }
41
51
  const allSensors = sensorsResult.data?.sensors?.data || [];
42
- const productionSensors = allSensors.filter(isProductionSensor);
43
- return { sites, buildings, floors, productionSensors };
52
+ return allSensors.filter(isProductionSensor);
53
+ }
54
+ /**
55
+ * Fetch specific sensors by ID.
56
+ *
57
+ * Unlike fetchProductionSensors this does NOT filter test devices: the caller
58
+ * asked for these exact IDs, so a mirror device has to come back so the caller
59
+ * can say so, rather than silently becoming "not found".
60
+ */
61
+ export async function fetchSensorsByIds(ids) {
62
+ if (ids.length === 0)
63
+ return [];
64
+ let result;
65
+ try {
66
+ result = await apolloClient.query({
67
+ query: GET_SENSORS_BY_IDS,
68
+ variables: { ids },
69
+ fetchPolicy: "network-only",
70
+ });
71
+ throwIfGraphQLErrors(result);
72
+ }
73
+ catch (error) {
74
+ rethrowIfGraphQLError(error);
75
+ throw error;
76
+ }
77
+ return result.data?.sensors?.data || [];
78
+ }
79
+ /**
80
+ * Fetch the sensors bound to specific rooms via `sensors(room_ids:)`.
81
+ *
82
+ * Like fetchSensorsByIds this does NOT filter test devices: the caller scoped
83
+ * the query to rooms it already knows about, and the row set has to be
84
+ * complete so the caller can apply whatever gate fits its use (e.g.
85
+ * isKnownTestSensor for a refusal gate that must not drop MAC-less
86
+ * placeholder rows).
87
+ */
88
+ export async function fetchSensorsByRoomIds(roomIds) {
89
+ if (roomIds.length === 0)
90
+ return [];
91
+ let result;
92
+ try {
93
+ result = await apolloClient.query({
94
+ query: GET_SENSORS_BY_ROOM_IDS,
95
+ variables: { roomIds },
96
+ fetchPolicy: "network-only",
97
+ });
98
+ throwIfGraphQLErrors(result);
99
+ }
100
+ catch (error) {
101
+ rethrowIfGraphQLError(error);
102
+ throw error;
103
+ }
104
+ return result.data?.sensors?.data || [];
105
+ }
106
+ /**
107
+ * Fetch topology and production sensors in a single parallel call.
108
+ * Shared by both current-occupancy and timeseries tools.
109
+ */
110
+ export async function fetchTopologyAndSensors() {
111
+ const [topology, productionSensors] = await Promise.all([
112
+ fetchTopology(),
113
+ fetchProductionSensors(),
114
+ ]);
115
+ return { ...topology, productionSensors };
44
116
  }
45
117
  /**
46
118
  * Resolve full context for an asset ID: type validation, name, timezone, sensor partitioning.
@@ -110,6 +182,45 @@ export function resolveAssetContext(assetId, ctx) {
110
182
  trafficSensors,
111
183
  };
112
184
  }
185
+ /**
186
+ * Resolve a single sensor's display name, timezone and breadcrumb path.
187
+ *
188
+ * Room first, floor second, for BOTH timezone and path. The room's own floor
189
+ * is authoritative: `sensor.floor_id` can be unset while `room_id` still
190
+ * resolves, and it can disagree with the room's actual floor. Keying the path
191
+ * off `floor_id` (while keying the timezone off `room_id`) drops every path
192
+ * segment in the first case and names the wrong floor in the second.
193
+ *
194
+ * Only snake_case linkage fields are read. Both queries that feed this
195
+ * (GET_ALL_SENSORS, GET_SENSORS_BY_IDS) select `floor_id`/`room_id` and not
196
+ * the camelCase resolvers, which are buggy for NULL values.
197
+ */
198
+ export function resolveSensorContext(sensor, ctx) {
199
+ const roomId = sensor.room_id || undefined;
200
+ const floorId = sensor.floor_id || undefined;
201
+ const floorByRoom = roomId
202
+ ? ctx.floors.find((f) => f.rooms?.some((r) => r.id === roomId))
203
+ : undefined;
204
+ const room = floorByRoom?.rooms?.find((r) => r.id === roomId);
205
+ const floor = floorByRoom ?? (floorId ? ctx.floors.find((f) => f.id === floorId) : undefined);
206
+ const building = floor ? ctx.buildings.find((b) => b.id === floor.building_id) : undefined;
207
+ // A dangling room reference (deleted room) falls through to the floor, and
208
+ // an unassigned sensor falls through to the UTC fallback with isFallback set.
209
+ const resolved = room
210
+ ? getTimezoneForAsset(room.id, "room", ctx.floors, ctx.buildings, ctx.sites)
211
+ : getTimezoneForAsset(floor?.id ?? "", "floor", ctx.floors, ctx.buildings, ctx.sites);
212
+ const name = sensor.name || sensor.id;
213
+ return {
214
+ name,
215
+ timezone: resolved.timezone,
216
+ tzMetadata: buildTimezoneMetadata(resolved.timezone),
217
+ timezoneFallback: resolved.isFallback,
218
+ path: [building?.name, floor?.name, room?.name, name].filter(Boolean).join(" > "),
219
+ room,
220
+ floor,
221
+ building,
222
+ };
223
+ }
113
224
  /**
114
225
  * Find the display name for an asset by searching the topology.
115
226
  */
@@ -1 +1 @@
1
- {"version":3,"file":"occupancy-helpers.js","sourceRoot":"","sources":["../../src/utils/occupancy-helpers.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"occupancy-helpers.js","sourceRoot":"","sources":["../../src/utils/occupancy-helpers.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Shared topology/device merge.
3
+ *
4
+ * Two tools need floors to carry their `sensors` and `hives` arrays:
5
+ * `butlr_list_topology` renders them, and `butlr_search_assets` flattens them
6
+ * into its search corpus. Keeping the merge in one place is what lets both
7
+ * read the same `devicesMerged: true` cache entry.
8
+ */
9
+ import type { Site, Sensor, Hive } from "../clients/types.js";
10
+ /**
11
+ * Merge sensors and hives into topology structure.
12
+ * Groups by floor_id and nests under appropriate floors.
13
+ *
14
+ * IN-PLACE MUTATION: assigns `floor.sensors` and `floor.hives` directly on
15
+ * the input site tree (returned for chaining; no new array is allocated).
16
+ * `setCachedTopology` reads from the same `sites` reference that this
17
+ * function mutates — any caller that captures the pre-merge `sites` (via
18
+ * Apollo cache-restore, structural clone, or fork-then-await) would
19
+ * observe the un-merged shape and could write a device-incomplete tree
20
+ * to the cache. If you change this to immutable assignment, audit the
21
+ * cache write site to confirm it sees the merged result.
22
+ */
23
+ export declare function mergeSensorsAndHivesIntoTopology(sites: Site[], allSensors: Sensor[], allHives: Hive[]): Site[];
24
+ //# sourceMappingURL=topology-merge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"topology-merge.d.ts","sourceRoot":"","sources":["../../src/utils/topology-merge.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,qBAAqB,CAAC;AAE9D;;;;;;;;;;;;GAYG;AACH,wBAAgB,gCAAgC,CAC9C,KAAK,EAAE,IAAI,EAAE,EACb,UAAU,EAAE,MAAM,EAAE,EACpB,QAAQ,EAAE,IAAI,EAAE,GACf,IAAI,EAAE,CAqCR"}
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Shared topology/device merge.
3
+ *
4
+ * Two tools need floors to carry their `sensors` and `hives` arrays:
5
+ * `butlr_list_topology` renders them, and `butlr_search_assets` flattens them
6
+ * into its search corpus. Keeping the merge in one place is what lets both
7
+ * read the same `devicesMerged: true` cache entry.
8
+ */
9
+ /**
10
+ * Merge sensors and hives into topology structure.
11
+ * Groups by floor_id and nests under appropriate floors.
12
+ *
13
+ * IN-PLACE MUTATION: assigns `floor.sensors` and `floor.hives` directly on
14
+ * the input site tree (returned for chaining; no new array is allocated).
15
+ * `setCachedTopology` reads from the same `sites` reference that this
16
+ * function mutates — any caller that captures the pre-merge `sites` (via
17
+ * Apollo cache-restore, structural clone, or fork-then-await) would
18
+ * observe the un-merged shape and could write a device-incomplete tree
19
+ * to the cache. If you change this to immutable assignment, audit the
20
+ * cache write site to confirm it sees the merged result.
21
+ */
22
+ export function mergeSensorsAndHivesIntoTopology(sites, allSensors, allHives) {
23
+ // Group sensors by floor_id
24
+ const sensorsByFloor = {};
25
+ for (const sensor of allSensors) {
26
+ const floorId = sensor.floor_id || sensor.floorID;
27
+ if (floorId) {
28
+ if (!sensorsByFloor[floorId]) {
29
+ sensorsByFloor[floorId] = [];
30
+ }
31
+ sensorsByFloor[floorId].push(sensor);
32
+ }
33
+ }
34
+ // Group hives by floor_id
35
+ const hivesByFloor = {};
36
+ for (const hive of allHives) {
37
+ const floorId = hive.floor_id || hive.floorID;
38
+ if (floorId) {
39
+ if (!hivesByFloor[floorId]) {
40
+ hivesByFloor[floorId] = [];
41
+ }
42
+ hivesByFloor[floorId].push(hive);
43
+ }
44
+ }
45
+ // Merge into topology
46
+ for (const site of sites) {
47
+ for (const building of site.buildings || []) {
48
+ for (const floor of building.floors || []) {
49
+ // Add sensors and hives to this floor
50
+ floor.sensors = sensorsByFloor[floor.id] || [];
51
+ floor.hives = hivesByFloor[floor.id] || [];
52
+ }
53
+ }
54
+ }
55
+ return sites;
56
+ }
57
+ //# sourceMappingURL=topology-merge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"topology-merge.js","sourceRoot":"","sources":["../../src/utils/topology-merge.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,gCAAgC,CAC9C,KAAa,EACb,UAAoB,EACpB,QAAgB;IAEhB,4BAA4B;IAC5B,MAAM,cAAc,GAA6B,EAAE,CAAC;IACpD,KAAK,MAAM,MAAM,IAAI,UAAU,EAAE,CAAC;QAChC,MAAM,OAAO,GAAG,MAAM,CAAC,QAAQ,IAAI,MAAM,CAAC,OAAO,CAAC;QAClD,IAAI,OAAO,EAAE,CAAC;YACZ,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,EAAE,CAAC;gBAC7B,cAAc,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC;YAC/B,CAAC;YACD,cAAc,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACvC,CAAC;IACH,CAAC;IAED,0BAA0B;IAC1B,MAAM,YAAY,GAA2B,EAAE,CAAC;IAChD,KAAK,MAAM,IAAI,IAAI,QAAQ,EAAE,CAAC;QAC5B,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,OAAO,CAAC;QAC9C,IAAI,OAAO,EAAE,CAAC;YACZ,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,EAAE,CAAC;gBAC3B,YAAY,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC;YAC7B,CAAC;YACD,YAAY,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACnC,CAAC;IACH,CAAC;IAED,sBAAsB;IACtB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,SAAS,IAAI,EAAE,EAAE,CAAC;YAC5C,KAAK,MAAM,KAAK,IAAI,QAAQ,CAAC,MAAM,IAAI,EAAE,EAAE,CAAC;gBAC1C,sCAAsC;gBACtC,KAAK,CAAC,OAAO,GAAG,cAAc,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC;gBAC/C,KAAK,CAAC,KAAK,GAAG,YAAY,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC;YAC7C,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC"}
package/llms.txt CHANGED
@@ -112,7 +112,7 @@ Users need edit access to Butlr Studio to create tokens. If they don't have edit
112
112
  - `butlr_hardware_snapshot` — Device health check: online/offline status and battery levels
113
113
  - `butlr_available_rooms` — Find currently unoccupied rooms, filterable by capacity and tags
114
114
  - `butlr_space_busyness` — Current occupancy with qualitative labels (quiet/moderate/busy) and trend comparison
115
- - `butlr_traffic_flow` — Entry/exit counts with hourly breakdown for traffic-mode sensors
115
+ - `butlr_traffic_flow` — Entry/exit counts with hourly breakdown, for a room or for one traffic-mode sensor. Accepts a room ID, a sensor ID (`sensor_...`) for per-access-point counts, or a name to search. A sensor does not need to be assigned to a room to be queried directly
116
116
  - `butlr_list_topology` — Display org hierarchy tree with flexible depth control
117
117
  - `butlr_fetch_entity_details` — Retrieve specific fields for entities by ID (minimal token usage)
118
118
  - `butlr_get_occupancy_timeseries` — Historical occupancy data with configurable time ranges
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@butlr/butlr-mcp-server",
3
- "version": "0.5.1",
3
+ "version": "0.6.0",
4
4
  "description": "Model Context Protocol server providing secure, read-only access to Butlr occupancy and asset data",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",