@butlr/butlr-mcp-server 0.5.0 → 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 (49) 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 +10 -0
  9. package/dist/clients/reporting-client.d.ts.map +1 -1
  10. package/dist/clients/reporting-client.js +11 -5
  11. package/dist/clients/reporting-client.js.map +1 -1
  12. package/dist/clients/types.d.ts +1 -1
  13. package/dist/clients/types.d.ts.map +1 -1
  14. package/dist/tools/butlr-list-topology.d.ts.map +1 -1
  15. package/dist/tools/butlr-list-topology.js +7 -53
  16. package/dist/tools/butlr-list-topology.js.map +1 -1
  17. package/dist/tools/butlr-search-assets.d.ts +1 -0
  18. package/dist/tools/butlr-search-assets.d.ts.map +1 -1
  19. package/dist/tools/butlr-search-assets.js +59 -15
  20. package/dist/tools/butlr-search-assets.js.map +1 -1
  21. package/dist/tools/butlr-traffic-flow.d.ts.map +1 -1
  22. package/dist/tools/butlr-traffic-flow.js +257 -59
  23. package/dist/tools/butlr-traffic-flow.js.map +1 -1
  24. package/dist/types/responses.d.ts +2 -1
  25. package/dist/types/responses.d.ts.map +1 -1
  26. package/dist/utils/asset-flattener.d.ts.map +1 -1
  27. package/dist/utils/asset-flattener.js +15 -3
  28. package/dist/utils/asset-flattener.js.map +1 -1
  29. package/dist/utils/graphql-helpers.d.ts +26 -1
  30. package/dist/utils/graphql-helpers.d.ts.map +1 -1
  31. package/dist/utils/graphql-helpers.js +30 -5
  32. package/dist/utils/graphql-helpers.js.map +1 -1
  33. package/dist/utils/occupancy-helpers.d.ts +72 -3
  34. package/dist/utils/occupancy-helpers.d.ts.map +1 -1
  35. package/dist/utils/occupancy-helpers.js +129 -18
  36. package/dist/utils/occupancy-helpers.js.map +1 -1
  37. package/dist/utils/time-range-validator.d.ts.map +1 -1
  38. package/dist/utils/time-range-validator.js +3 -32
  39. package/dist/utils/time-range-validator.js.map +1 -1
  40. package/dist/utils/time-resolver.d.ts +18 -0
  41. package/dist/utils/time-resolver.d.ts.map +1 -0
  42. package/dist/utils/time-resolver.js +44 -0
  43. package/dist/utils/time-resolver.js.map +1 -0
  44. package/dist/utils/topology-merge.d.ts +24 -0
  45. package/dist/utils/topology-merge.d.ts.map +1 -0
  46. package/dist/utils/topology-merge.js +57 -0
  47. package/dist/utils/topology-merge.js.map +1 -0
  48. package/llms.txt +1 -1
  49. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"time-range-validator.d.ts","sourceRoot":"","sources":["../../src/utils/time-range-validator.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAiCrF"}
1
+ {"version":3,"file":"time-range-validator.d.ts","sourceRoot":"","sources":["../../src/utils/time-range-validator.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAiCrF"}
@@ -2,6 +2,7 @@
2
2
  * Time range validation for timeseries queries
3
3
  * Prevents excessive data queries that could timeout or overwhelm the API
4
4
  */
5
+ import { parseTimeString } from "./time-resolver.js";
5
6
  /**
6
7
  * Validate time range based on interval
7
8
  * @param interval Aggregation interval ('1m', '1h', '1d')
@@ -11,8 +12,8 @@
11
12
  */
12
13
  export function validateTimeRange(interval, start, stop) {
13
14
  // Parse times - handle relative times by converting to absolute
14
- const startTime = parseTime(start);
15
- const stopTime = parseTime(stop);
15
+ const startTime = parseTimeString(start);
16
+ const stopTime = parseTimeString(stop);
16
17
  // Calculate duration in hours
17
18
  const durationMs = stopTime.getTime() - startTime.getTime();
18
19
  const durationHours = durationMs / (1000 * 60 * 60);
@@ -32,34 +33,4 @@ export function validateTimeRange(interval, start, stop) {
32
33
  throw new Error(`Start time must be before stop time. Start: ${start}, Stop: ${stop}`);
33
34
  }
34
35
  }
35
- /**
36
- * Parse time string (ISO-8601 or relative) to Date
37
- */
38
- function parseTime(timeStr) {
39
- // Handle relative times like '-24h', '-1d', 'now'
40
- if (timeStr === "now") {
41
- return new Date();
42
- }
43
- // Relative time pattern: -<number><unit>
44
- const relativeMatch = timeStr.match(/^-(\d+)(m|h|d)$/);
45
- if (relativeMatch) {
46
- const amount = parseInt(relativeMatch[1], 10);
47
- const unit = relativeMatch[2];
48
- const now = new Date();
49
- switch (unit) {
50
- case "m":
51
- return new Date(now.getTime() - amount * 60 * 1000);
52
- case "h":
53
- return new Date(now.getTime() - amount * 60 * 60 * 1000);
54
- case "d":
55
- return new Date(now.getTime() - amount * 24 * 60 * 60 * 1000);
56
- }
57
- }
58
- // Try parsing as ISO-8601
59
- const parsed = new Date(timeStr);
60
- if (isNaN(parsed.getTime())) {
61
- throw new Error(`Invalid time format: ${timeStr}. Use ISO-8601 or relative format like '-24h'.`);
62
- }
63
- return parsed;
64
- }
65
36
  //# sourceMappingURL=time-range-validator.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"time-range-validator.js","sourceRoot":"","sources":["../../src/utils/time-range-validator.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;;;GAMG;AACH,MAAM,UAAU,iBAAiB,CAAC,QAAgB,EAAE,KAAa,EAAE,IAAY;IAC7E,gEAAgE;IAChE,MAAM,SAAS,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC;IACnC,MAAM,QAAQ,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;IAEjC,8BAA8B;IAC9B,MAAM,UAAU,GAAG,QAAQ,CAAC,OAAO,EAAE,GAAG,SAAS,CAAC,OAAO,EAAE,CAAC;IAC5D,MAAM,aAAa,GAAG,UAAU,GAAG,CAAC,IAAI,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC;IACpD,MAAM,YAAY,GAAG,aAAa,GAAG,EAAE,CAAC;IAExC,6BAA6B;IAC7B,IAAI,QAAQ,KAAK,IAAI,IAAI,aAAa,GAAG,CAAC,EAAE,CAAC;QAC3C,MAAM,IAAI,KAAK,CACb,qEAAqE,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CACvG,CAAC;IACJ,CAAC;IAED,IAAI,QAAQ,KAAK,IAAI,IAAI,aAAa,GAAG,EAAE,EAAE,CAAC;QAC5C,MAAM,IAAI,KAAK,CACb,uEAAuE,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CACzG,CAAC;IACJ,CAAC;IAED,IAAI,QAAQ,KAAK,IAAI,IAAI,YAAY,GAAG,EAAE,EAAE,CAAC;QAC3C,MAAM,IAAI,KAAK,CACb,sEAAsE,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CACtG,CAAC;IACJ,CAAC;IAED,gCAAgC;IAChC,IAAI,SAAS,IAAI,QAAQ,EAAE,CAAC;QAC1B,MAAM,IAAI,KAAK,CAAC,+CAA+C,KAAK,WAAW,IAAI,EAAE,CAAC,CAAC;IACzF,CAAC;AACH,CAAC;AAED;;GAEG;AACH,SAAS,SAAS,CAAC,OAAe;IAChC,kDAAkD;IAClD,IAAI,OAAO,KAAK,KAAK,EAAE,CAAC;QACtB,OAAO,IAAI,IAAI,EAAE,CAAC;IACpB,CAAC;IAED,yCAAyC;IACzC,MAAM,aAAa,GAAG,OAAO,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC;IACvD,IAAI,aAAa,EAAE,CAAC;QAClB,MAAM,MAAM,GAAG,QAAQ,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QAC9C,MAAM,IAAI,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC;QAC9B,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;QAEvB,QAAQ,IAAI,EAAE,CAAC;YACb,KAAK,GAAG;gBACN,OAAO,IAAI,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,MAAM,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;YACtD,KAAK,GAAG;gBACN,OAAO,IAAI,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,MAAM,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;YAC3D,KAAK,GAAG;gBACN,OAAO,IAAI,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,MAAM,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;QAClE,CAAC;IACH,CAAC;IAED,0BAA0B;IAC1B,MAAM,MAAM,GAAG,IAAI,IAAI,CAAC,OAAO,CAAC,CAAC;IACjC,IAAI,KAAK,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC;QAC5B,MAAM,IAAI,KAAK,CACb,wBAAwB,OAAO,gDAAgD,CAChF,CAAC;IACJ,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
1
+ {"version":3,"file":"time-range-validator.js","sourceRoot":"","sources":["../../src/utils/time-range-validator.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAErD;;;;;;GAMG;AACH,MAAM,UAAU,iBAAiB,CAAC,QAAgB,EAAE,KAAa,EAAE,IAAY;IAC7E,gEAAgE;IAChE,MAAM,SAAS,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC;IACzC,MAAM,QAAQ,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC;IAEvC,8BAA8B;IAC9B,MAAM,UAAU,GAAG,QAAQ,CAAC,OAAO,EAAE,GAAG,SAAS,CAAC,OAAO,EAAE,CAAC;IAC5D,MAAM,aAAa,GAAG,UAAU,GAAG,CAAC,IAAI,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC;IACpD,MAAM,YAAY,GAAG,aAAa,GAAG,EAAE,CAAC;IAExC,6BAA6B;IAC7B,IAAI,QAAQ,KAAK,IAAI,IAAI,aAAa,GAAG,CAAC,EAAE,CAAC;QAC3C,MAAM,IAAI,KAAK,CACb,qEAAqE,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CACvG,CAAC;IACJ,CAAC;IAED,IAAI,QAAQ,KAAK,IAAI,IAAI,aAAa,GAAG,EAAE,EAAE,CAAC;QAC5C,MAAM,IAAI,KAAK,CACb,uEAAuE,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CACzG,CAAC;IACJ,CAAC;IAED,IAAI,QAAQ,KAAK,IAAI,IAAI,YAAY,GAAG,EAAE,EAAE,CAAC;QAC3C,MAAM,IAAI,KAAK,CACb,sEAAsE,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CACtG,CAAC;IACJ,CAAC;IAED,gCAAgC;IAChC,IAAI,SAAS,IAAI,QAAQ,EAAE,CAAC;QAC1B,MAAM,IAAI,KAAK,CAAC,+CAA+C,KAAK,WAAW,IAAI,EAAE,CAAC,CAAC;IACzF,CAAC;AACH,CAAC"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Time string parsing shared by request builders and validators.
3
+ *
4
+ * The v3 reporting API (ETL backend since the Aug 2026 cutover) accepts only
5
+ * RFC3339 timestamps: relative forms like "-20m" are rejected with a 400, and
6
+ * omitting filter.stop returns an empty result set. All times must be
7
+ * resolved to absolute timestamps client-side before sending.
8
+ */
9
+ /**
10
+ * Parse a time string ("now", relative like "-24h", or ISO-8601) to a Date.
11
+ * @throws Error if the string is not a recognized time format
12
+ */
13
+ export declare function parseTimeString(timeStr: string): Date;
14
+ /**
15
+ * Resolve a time string to an absolute ISO-8601 timestamp string.
16
+ */
17
+ export declare function resolveTimeToIso(timeStr: string): string;
18
+ //# sourceMappingURL=time-resolver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"time-resolver.d.ts","sourceRoot":"","sources":["../../src/utils/time-resolver.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH;;;GAGG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CA8BrD;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAExD"}
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Time string parsing shared by request builders and validators.
3
+ *
4
+ * The v3 reporting API (ETL backend since the Aug 2026 cutover) accepts only
5
+ * RFC3339 timestamps: relative forms like "-20m" are rejected with a 400, and
6
+ * omitting filter.stop returns an empty result set. All times must be
7
+ * resolved to absolute timestamps client-side before sending.
8
+ */
9
+ /**
10
+ * Parse a time string ("now", relative like "-24h", or ISO-8601) to a Date.
11
+ * @throws Error if the string is not a recognized time format
12
+ */
13
+ export function parseTimeString(timeStr) {
14
+ if (timeStr === "now") {
15
+ return new Date();
16
+ }
17
+ // Relative time pattern: -<number><unit>
18
+ const relativeMatch = timeStr.match(/^-(\d+)(m|h|d)$/);
19
+ if (relativeMatch) {
20
+ const amount = parseInt(relativeMatch[1], 10);
21
+ const unit = relativeMatch[2];
22
+ const now = new Date();
23
+ switch (unit) {
24
+ case "m":
25
+ return new Date(now.getTime() - amount * 60 * 1000);
26
+ case "h":
27
+ return new Date(now.getTime() - amount * 60 * 60 * 1000);
28
+ case "d":
29
+ return new Date(now.getTime() - amount * 24 * 60 * 60 * 1000);
30
+ }
31
+ }
32
+ const parsed = new Date(timeStr);
33
+ if (isNaN(parsed.getTime())) {
34
+ throw new Error(`Invalid time format: ${timeStr}. Use ISO-8601 or relative format like '-24h'.`);
35
+ }
36
+ return parsed;
37
+ }
38
+ /**
39
+ * Resolve a time string to an absolute ISO-8601 timestamp string.
40
+ */
41
+ export function resolveTimeToIso(timeStr) {
42
+ return parseTimeString(timeStr).toISOString();
43
+ }
44
+ //# sourceMappingURL=time-resolver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"time-resolver.js","sourceRoot":"","sources":["../../src/utils/time-resolver.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,OAAe;IAC7C,IAAI,OAAO,KAAK,KAAK,EAAE,CAAC;QACtB,OAAO,IAAI,IAAI,EAAE,CAAC;IACpB,CAAC;IAED,yCAAyC;IACzC,MAAM,aAAa,GAAG,OAAO,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC;IACvD,IAAI,aAAa,EAAE,CAAC;QAClB,MAAM,MAAM,GAAG,QAAQ,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QAC9C,MAAM,IAAI,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC;QAC9B,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;QAEvB,QAAQ,IAAI,EAAE,CAAC;YACb,KAAK,GAAG;gBACN,OAAO,IAAI,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,MAAM,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;YACtD,KAAK,GAAG;gBACN,OAAO,IAAI,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,MAAM,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;YAC3D,KAAK,GAAG;gBACN,OAAO,IAAI,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,MAAM,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;QAClE,CAAC;IACH,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,IAAI,CAAC,OAAO,CAAC,CAAC;IACjC,IAAI,KAAK,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC;QAC5B,MAAM,IAAI,KAAK,CACb,wBAAwB,OAAO,gDAAgD,CAChF,CAAC;IACJ,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAAC,OAAe;IAC9C,OAAO,eAAe,CAAC,OAAO,CAAC,CAAC,WAAW,EAAE,CAAC;AAChD,CAAC"}
@@ -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.0",
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",