@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.
- package/README.md +1 -1
- package/dist/cache/topology-cache.d.ts +6 -6
- package/dist/cache/topology-cache.js +6 -6
- package/dist/clients/queries/topology.d.ts +14 -0
- package/dist/clients/queries/topology.d.ts.map +1 -1
- package/dist/clients/queries/topology.js +48 -0
- package/dist/clients/queries/topology.js.map +1 -1
- package/dist/clients/reporting-client.d.ts +10 -0
- package/dist/clients/reporting-client.d.ts.map +1 -1
- package/dist/clients/reporting-client.js +11 -5
- package/dist/clients/reporting-client.js.map +1 -1
- package/dist/clients/types.d.ts +1 -1
- package/dist/clients/types.d.ts.map +1 -1
- package/dist/tools/butlr-list-topology.d.ts.map +1 -1
- package/dist/tools/butlr-list-topology.js +7 -53
- package/dist/tools/butlr-list-topology.js.map +1 -1
- package/dist/tools/butlr-search-assets.d.ts +1 -0
- package/dist/tools/butlr-search-assets.d.ts.map +1 -1
- package/dist/tools/butlr-search-assets.js +59 -15
- package/dist/tools/butlr-search-assets.js.map +1 -1
- package/dist/tools/butlr-traffic-flow.d.ts.map +1 -1
- package/dist/tools/butlr-traffic-flow.js +257 -59
- package/dist/tools/butlr-traffic-flow.js.map +1 -1
- package/dist/types/responses.d.ts +2 -1
- package/dist/types/responses.d.ts.map +1 -1
- package/dist/utils/asset-flattener.d.ts.map +1 -1
- package/dist/utils/asset-flattener.js +15 -3
- package/dist/utils/asset-flattener.js.map +1 -1
- package/dist/utils/graphql-helpers.d.ts +26 -1
- package/dist/utils/graphql-helpers.d.ts.map +1 -1
- package/dist/utils/graphql-helpers.js +30 -5
- package/dist/utils/graphql-helpers.js.map +1 -1
- package/dist/utils/occupancy-helpers.d.ts +72 -3
- package/dist/utils/occupancy-helpers.d.ts.map +1 -1
- package/dist/utils/occupancy-helpers.js +129 -18
- package/dist/utils/occupancy-helpers.js.map +1 -1
- package/dist/utils/time-range-validator.d.ts.map +1 -1
- package/dist/utils/time-range-validator.js +3 -32
- package/dist/utils/time-range-validator.js.map +1 -1
- package/dist/utils/time-resolver.d.ts +18 -0
- package/dist/utils/time-resolver.d.ts.map +1 -0
- package/dist/utils/time-resolver.js +44 -0
- package/dist/utils/time-resolver.js.map +1 -0
- package/dist/utils/topology-merge.d.ts +24 -0
- package/dist/utils/topology-merge.d.ts.map +1 -0
- package/dist/utils/topology-merge.js +57 -0
- package/dist/utils/topology-merge.js.map +1 -0
- package/llms.txt +1 -1
- 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;
|
|
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 =
|
|
15
|
-
const stopTime =
|
|
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,
|
|
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
|
|
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