@butlr/butlr-mcp-server 0.1.2 → 0.4.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 +27 -1
- package/dist/cache/topology-cache.d.ts +18 -3
- package/dist/cache/topology-cache.d.ts.map +1 -1
- package/dist/cache/topology-cache.js +19 -3
- package/dist/cache/topology-cache.js.map +1 -1
- package/dist/clients/queries/tags.d.ts +96 -0
- package/dist/clients/queries/tags.d.ts.map +1 -0
- package/dist/clients/queries/tags.js +64 -0
- package/dist/clients/queries/tags.js.map +1 -0
- package/dist/clients/types.d.ts +6 -2
- package/dist/clients/types.d.ts.map +1 -1
- package/dist/errors/mcp-errors.d.ts +34 -0
- package/dist/errors/mcp-errors.d.ts.map +1 -1
- package/dist/errors/mcp-errors.js +71 -5
- package/dist/errors/mcp-errors.js.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/tools/butlr-available-rooms.d.ts +10 -4
- package/dist/tools/butlr-available-rooms.d.ts.map +1 -1
- package/dist/tools/butlr-available-rooms.js +177 -45
- package/dist/tools/butlr-available-rooms.js.map +1 -1
- package/dist/tools/butlr-fetch-entity-details.d.ts.map +1 -1
- package/dist/tools/butlr-fetch-entity-details.js +7 -1
- package/dist/tools/butlr-fetch-entity-details.js.map +1 -1
- package/dist/tools/butlr-get-asset-details.d.ts.map +1 -1
- package/dist/tools/butlr-get-asset-details.js +29 -4
- package/dist/tools/butlr-get-asset-details.js.map +1 -1
- package/dist/tools/butlr-get-current-occupancy.d.ts.map +1 -1
- package/dist/tools/butlr-get-current-occupancy.js +27 -6
- package/dist/tools/butlr-get-current-occupancy.js.map +1 -1
- package/dist/tools/butlr-get-occupancy-timeseries.d.ts.map +1 -1
- package/dist/tools/butlr-get-occupancy-timeseries.js +32 -11
- package/dist/tools/butlr-get-occupancy-timeseries.js.map +1 -1
- package/dist/tools/butlr-list-tags.d.ts +50 -0
- package/dist/tools/butlr-list-tags.d.ts.map +1 -0
- package/dist/tools/butlr-list-tags.js +165 -0
- package/dist/tools/butlr-list-tags.js.map +1 -0
- package/dist/tools/butlr-list-topology.d.ts +7 -1
- package/dist/tools/butlr-list-topology.d.ts.map +1 -1
- package/dist/tools/butlr-list-topology.js +845 -35
- package/dist/tools/butlr-list-topology.js.map +1 -1
- package/dist/tools/butlr-search-assets.d.ts.map +1 -1
- package/dist/tools/butlr-search-assets.js +7 -1
- package/dist/tools/butlr-search-assets.js.map +1 -1
- package/dist/tools/butlr-space-busyness.d.ts.map +1 -1
- package/dist/tools/butlr-space-busyness.js +30 -5
- package/dist/tools/butlr-space-busyness.js.map +1 -1
- package/dist/tools/butlr-traffic-flow.d.ts.map +1 -1
- package/dist/tools/butlr-traffic-flow.js +14 -9
- package/dist/tools/butlr-traffic-flow.js.map +1 -1
- package/dist/types/responses.d.ts +126 -4
- package/dist/types/responses.d.ts.map +1 -1
- package/dist/utils/asset-flattener.js +2 -2
- package/dist/utils/asset-flattener.js.map +1 -1
- package/dist/utils/field-validator.d.ts.map +1 -1
- package/dist/utils/field-validator.js +3 -0
- package/dist/utils/field-validator.js.map +1 -1
- package/dist/utils/graphql-helpers.d.ts +13 -0
- package/dist/utils/graphql-helpers.d.ts.map +1 -1
- package/dist/utils/graphql-helpers.js +25 -0
- package/dist/utils/graphql-helpers.js.map +1 -1
- package/dist/utils/occupancy-helpers.d.ts +2 -0
- package/dist/utils/occupancy-helpers.d.ts.map +1 -1
- package/dist/utils/occupancy-helpers.js +26 -9
- package/dist/utils/occupancy-helpers.js.map +1 -1
- package/dist/utils/tag-resolver.d.ts +99 -0
- package/dist/utils/tag-resolver.d.ts.map +1 -0
- package/dist/utils/tag-resolver.js +108 -0
- package/dist/utils/tag-resolver.js.map +1 -0
- package/dist/utils/timezone-helpers.d.ts +8 -3
- package/dist/utils/timezone-helpers.d.ts.map +1 -1
- package/dist/utils/timezone-helpers.js +22 -14
- package/dist/utils/timezone-helpers.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -18,7 +18,7 @@ A [Model Context Protocol](https://modelcontextprotocol.io) (MCP) server that co
|
|
|
18
18
|
## Prerequisites
|
|
19
19
|
|
|
20
20
|
- [Node.js](https://nodejs.org/) 18 or higher
|
|
21
|
-
- An MCP-compatible client ([Claude Desktop](https://claude.ai/download), [Claude Code](https://docs.anthropic.com/en/docs/claude-code), [VS Code](https://code.visualstudio.com/), [Cursor](https://cursor.com/), etc.)
|
|
21
|
+
- An MCP-compatible client ([Claude Desktop](https://claude.ai/download), [Claude Code](https://docs.anthropic.com/en/docs/claude-code), [Codex CLI](https://developers.openai.com/codex/cli), [VS Code](https://code.visualstudio.com/), [Cursor](https://cursor.com/), etc.)
|
|
22
22
|
- Butlr API token — see [Getting API Credentials](#getting-api-credentials)
|
|
23
23
|
|
|
24
24
|
## Quick Start
|
|
@@ -57,6 +57,32 @@ claude mcp add butlr \
|
|
|
57
57
|
|
|
58
58
|
</details>
|
|
59
59
|
|
|
60
|
+
<details>
|
|
61
|
+
<summary><strong>Codex CLI</strong></summary>
|
|
62
|
+
|
|
63
|
+
Add with the `codex mcp` command:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
codex mcp add butlr \
|
|
67
|
+
--env BUTLR_CLIENT_ID=your_client_id \
|
|
68
|
+
--env BUTLR_CLIENT_SECRET=your_client_secret \
|
|
69
|
+
-- npx -y @butlr/butlr-mcp-server@latest
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Or edit `~/.codex/config.toml` directly:
|
|
73
|
+
|
|
74
|
+
```toml
|
|
75
|
+
[mcp_servers.butlr]
|
|
76
|
+
command = "npx"
|
|
77
|
+
args = ["-y", "@butlr/butlr-mcp-server@latest"]
|
|
78
|
+
|
|
79
|
+
[mcp_servers.butlr.env]
|
|
80
|
+
BUTLR_CLIENT_ID = "your_client_id"
|
|
81
|
+
BUTLR_CLIENT_SECRET = "your_client_secret"
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
</details>
|
|
85
|
+
|
|
60
86
|
<details>
|
|
61
87
|
<summary><strong>VS Code (Copilot)</strong></summary>
|
|
62
88
|
|
|
@@ -9,15 +9,30 @@ interface CacheEntry {
|
|
|
9
9
|
*/
|
|
10
10
|
export declare const topologyCache: LRUCache<string, CacheEntry, unknown>;
|
|
11
11
|
/**
|
|
12
|
-
* Generate cache key for topology queries
|
|
12
|
+
* Generate cache key for topology queries.
|
|
13
|
+
*
|
|
14
|
+
* `devicesMerged` is part of the key because two consumers prime this cache
|
|
15
|
+
* with different shapes: `butlr_list_topology` runs sensors/hives through
|
|
16
|
+
* `mergeSensorsAndHivesIntoTopology` (so every floor carries `sensors` and
|
|
17
|
+
* `hives` arrays); `butlr_search_assets` writes the raw `sites` tree
|
|
18
|
+
* unmodified. A device-aware reader cannot trust an unmerged entry, so the
|
|
19
|
+
* two shapes must live under separate keys.
|
|
13
20
|
*/
|
|
14
|
-
export declare function generateTopologyCacheKey(orgId: string, includeDevices: boolean, includeZones: boolean, siteIds?: string[]): string;
|
|
21
|
+
export declare function generateTopologyCacheKey(orgId: string, includeDevices: boolean, includeZones: boolean, devicesMerged: boolean, siteIds?: string[]): string;
|
|
15
22
|
/**
|
|
16
23
|
* Get cached topology data
|
|
17
24
|
*/
|
|
18
25
|
export declare function getCachedTopology(key: string): CacheEntry | undefined;
|
|
19
26
|
/**
|
|
20
|
-
* Store topology data in cache
|
|
27
|
+
* Store topology data in cache.
|
|
28
|
+
*
|
|
29
|
+
* INVARIANT: callers MUST only cache COMPLETE topology. A partial fetch
|
|
30
|
+
* (Apollo `result.error` set, GraphQL returned errors alongside data) will
|
|
31
|
+
* silently launder its partiality through the cache otherwise — every
|
|
32
|
+
* subsequent cache-hit reader would treat the truncated tree as
|
|
33
|
+
* authoritative without seeing `partial_topology`. `butlr-list-topology`
|
|
34
|
+
* gates its `setCachedTopology` call on `!partialData`; any new caller
|
|
35
|
+
* must do the same.
|
|
21
36
|
*/
|
|
22
37
|
export declare function setCachedTopology(key: string, data: Record<string, unknown>): void;
|
|
23
38
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"topology-cache.d.ts","sourceRoot":"","sources":["../../src/cache/topology-cache.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AASrC,UAAU,UAAU;IAClB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9B,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;GAGG;AACH,eAAO,MAAM,aAAa,uCAKxB,CAAC;AAEH
|
|
1
|
+
{"version":3,"file":"topology-cache.d.ts","sourceRoot":"","sources":["../../src/cache/topology-cache.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AASrC,UAAU,UAAU;IAClB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9B,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;GAGG;AACH,eAAO,MAAM,aAAa,uCAKxB,CAAC;AAEH;;;;;;;;;GASG;AACH,wBAAgB,wBAAwB,CACtC,KAAK,EAAE,MAAM,EACb,cAAc,EAAE,OAAO,EACvB,YAAY,EAAE,OAAO,EACrB,aAAa,EAAE,OAAO,EACtB,OAAO,CAAC,EAAE,MAAM,EAAE,GACjB,MAAM,CAYR;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,CAUrE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CASlF;AAED;;GAEG;AACH,wBAAgB,kBAAkB,IAAI,IAAI,CAIzC;AAED;;GAEG;AACH,wBAAgB,aAAa;;;;EAM5B"}
|
|
@@ -16,15 +16,23 @@ export const topologyCache = new LRUCache({
|
|
|
16
16
|
updateAgeOnHas: false,
|
|
17
17
|
});
|
|
18
18
|
/**
|
|
19
|
-
* Generate cache key for topology queries
|
|
19
|
+
* Generate cache key for topology queries.
|
|
20
|
+
*
|
|
21
|
+
* `devicesMerged` is part of the key because two consumers prime this cache
|
|
22
|
+
* with different shapes: `butlr_list_topology` runs sensors/hives through
|
|
23
|
+
* `mergeSensorsAndHivesIntoTopology` (so every floor carries `sensors` and
|
|
24
|
+
* `hives` arrays); `butlr_search_assets` writes the raw `sites` tree
|
|
25
|
+
* unmodified. A device-aware reader cannot trust an unmerged entry, so the
|
|
26
|
+
* two shapes must live under separate keys.
|
|
20
27
|
*/
|
|
21
|
-
export function generateTopologyCacheKey(orgId, includeDevices, includeZones, siteIds) {
|
|
28
|
+
export function generateTopologyCacheKey(orgId, includeDevices, includeZones, devicesMerged, siteIds) {
|
|
22
29
|
const parts = ["topo", orgId];
|
|
23
30
|
if (siteIds && siteIds.length > 0) {
|
|
24
31
|
parts.push(`sites:${siteIds.sort().join(",")}`);
|
|
25
32
|
}
|
|
26
33
|
parts.push(`devices:${includeDevices}`);
|
|
27
34
|
parts.push(`zones:${includeZones}`);
|
|
35
|
+
parts.push(`merged:${devicesMerged}`);
|
|
28
36
|
return parts.join(":");
|
|
29
37
|
}
|
|
30
38
|
/**
|
|
@@ -41,7 +49,15 @@ export function getCachedTopology(key) {
|
|
|
41
49
|
return cached;
|
|
42
50
|
}
|
|
43
51
|
/**
|
|
44
|
-
* Store topology data in cache
|
|
52
|
+
* Store topology data in cache.
|
|
53
|
+
*
|
|
54
|
+
* INVARIANT: callers MUST only cache COMPLETE topology. A partial fetch
|
|
55
|
+
* (Apollo `result.error` set, GraphQL returned errors alongside data) will
|
|
56
|
+
* silently launder its partiality through the cache otherwise — every
|
|
57
|
+
* subsequent cache-hit reader would treat the truncated tree as
|
|
58
|
+
* authoritative without seeing `partial_topology`. `butlr-list-topology`
|
|
59
|
+
* gates its `setCachedTopology` call on `!partialData`; any new caller
|
|
60
|
+
* must do the same.
|
|
45
61
|
*/
|
|
46
62
|
export function setCachedTopology(key, data) {
|
|
47
63
|
const entry = {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"topology-cache.js","sourceRoot":"","sources":["../../src/cache/topology-cache.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AACrC,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAE1C;;GAEG;AACH,MAAM,iBAAiB,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,kBAAkB,IAAI,KAAK,EAAE,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC,0BAA0B;AAClH,MAAM,iBAAiB,GAAG,GAAG,CAAC;AAO9B;;;GAGG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,IAAI,QAAQ,CAAqB;IAC5D,GAAG,EAAE,iBAAiB;IACtB,GAAG,EAAE,iBAAiB;IACtB,cAAc,EAAE,IAAI,EAAE,yBAAyB;IAC/C,cAAc,EAAE,KAAK;CACtB,CAAC,CAAC;AAEH
|
|
1
|
+
{"version":3,"file":"topology-cache.js","sourceRoot":"","sources":["../../src/cache/topology-cache.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AACrC,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAE1C;;GAEG;AACH,MAAM,iBAAiB,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,kBAAkB,IAAI,KAAK,EAAE,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC,0BAA0B;AAClH,MAAM,iBAAiB,GAAG,GAAG,CAAC;AAO9B;;;GAGG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,IAAI,QAAQ,CAAqB;IAC5D,GAAG,EAAE,iBAAiB;IACtB,GAAG,EAAE,iBAAiB;IACtB,cAAc,EAAE,IAAI,EAAE,yBAAyB;IAC/C,cAAc,EAAE,KAAK;CACtB,CAAC,CAAC;AAEH;;;;;;;;;GASG;AACH,MAAM,UAAU,wBAAwB,CACtC,KAAa,EACb,cAAuB,EACvB,YAAqB,EACrB,aAAsB,EACtB,OAAkB;IAElB,MAAM,KAAK,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IAE9B,IAAI,OAAO,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAClC,KAAK,CAAC,IAAI,CAAC,SAAS,OAAO,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAClD,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,WAAW,cAAc,EAAE,CAAC,CAAC;IACxC,KAAK,CAAC,IAAI,CAAC,SAAS,YAAY,EAAE,CAAC,CAAC;IACpC,KAAK,CAAC,IAAI,CAAC,UAAU,aAAa,EAAE,CAAC,CAAC;IAEtC,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACzB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,iBAAiB,CAAC,GAAW;IAC3C,MAAM,MAAM,GAAG,aAAa,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAEtC,IAAI,MAAM,EAAE,CAAC;QACX,KAAK,CAAC,gBAAgB,EAAE,sBAAsB,GAAG,EAAE,CAAC,CAAC;IACvD,CAAC;SAAM,CAAC;QACN,KAAK,CAAC,gBAAgB,EAAE,uBAAuB,GAAG,EAAE,CAAC,CAAC;IACxD,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,iBAAiB,CAAC,GAAW,EAAE,IAA6B;IAC1E,MAAM,KAAK,GAAe;QACxB,IAAI;QACJ,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KACpC,CAAC;IAEF,aAAa,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IAE9B,KAAK,CAAC,gBAAgB,EAAE,wBAAwB,GAAG,UAAU,iBAAiB,GAAG,IAAI,IAAI,CAAC,CAAC;AAC7F,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,kBAAkB;IAChC,aAAa,CAAC,KAAK,EAAE,CAAC;IAEtB,KAAK,CAAC,gBAAgB,EAAE,eAAe,CAAC,CAAC;AAC3C,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,aAAa;IAC3B,OAAO;QACL,IAAI,EAAE,aAAa,CAAC,IAAI;QACxB,OAAO,EAAE,iBAAiB;QAC1B,GAAG,EAAE,iBAAiB,GAAG,IAAI,EAAE,sCAAsC;KACtE,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GraphQL queries for tag retrieval and lookups.
|
|
3
|
+
*
|
|
4
|
+
* Tags are org-scoped: a single tag (id, name, organization_id) can be
|
|
5
|
+
* applied to any combination of rooms, zones, and floors via separate
|
|
6
|
+
* association tables. There is no per-level tag namespace.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Branded string types for tag identifiers.
|
|
10
|
+
*
|
|
11
|
+
* The Butlr API filter `roomsByTag` accepts tag *IDs*, not tag *names*.
|
|
12
|
+
* Both are `string` at runtime, which previously led to silent filter
|
|
13
|
+
* failures when names were sent in the IDs slot. Branding them keeps the
|
|
14
|
+
* distinction visible at the type level so the wrong one cannot be passed
|
|
15
|
+
* by accident.
|
|
16
|
+
*/
|
|
17
|
+
export type TagId = string & {
|
|
18
|
+
readonly __brand: "TagId";
|
|
19
|
+
};
|
|
20
|
+
export type TagName = string & {
|
|
21
|
+
readonly __brand: "TagName";
|
|
22
|
+
};
|
|
23
|
+
/** Multi-tag composition mode shared across every tag-aware tool surface. */
|
|
24
|
+
export type TagMatch = "all" | "any";
|
|
25
|
+
/**
|
|
26
|
+
* Brand a string as a tag id. Throws on empty/whitespace-only input — the
|
|
27
|
+
* brand exists to catch "wrong slot" mistakes at compile time, but a blank
|
|
28
|
+
* value would brand cleanly and slip through. Constructors that accept
|
|
29
|
+
* arbitrary strings need a runtime check too.
|
|
30
|
+
*/
|
|
31
|
+
export declare const asTagId: (value: string) => TagId;
|
|
32
|
+
/** Brand a string as a tag name. Same empty-input guard as `asTagId`. */
|
|
33
|
+
export declare const asTagName: (value: string) => TagName;
|
|
34
|
+
/**
|
|
35
|
+
* Shape of each tagged-entity reference returned by `GET_TAGS_WITH_USAGE`.
|
|
36
|
+
* `name` is best-effort: older API responses or partial entity records may
|
|
37
|
+
* omit it, so consumers must treat it as optional.
|
|
38
|
+
*
|
|
39
|
+
* Both `id` and `name` are runtime-guarded against partial GraphQL
|
|
40
|
+
* responses by `projectValidRefs` (src/utils/tag-resolver.ts) — refs with
|
|
41
|
+
* a missing/null/empty `id` are dropped, and a missing `name` is elided
|
|
42
|
+
* from the projection. Consumers should route through `projectValidRefs`
|
|
43
|
+
* rather than reading the fields directly, even though the type declares
|
|
44
|
+
* `id` as required.
|
|
45
|
+
*/
|
|
46
|
+
export interface TaggedEntityRef {
|
|
47
|
+
id: string;
|
|
48
|
+
name?: string;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Raw `tags` row returned by `GET_TAGS_WITH_USAGE`. Used by `butlr_list_tags`
|
|
52
|
+
* and the shared tag resolver — kept here so the GraphQL shape lives next
|
|
53
|
+
* to the query that produces it.
|
|
54
|
+
*/
|
|
55
|
+
export interface RawTagWithUsage {
|
|
56
|
+
id: string;
|
|
57
|
+
name: string;
|
|
58
|
+
organization_id?: string;
|
|
59
|
+
rooms?: TaggedEntityRef[] | null;
|
|
60
|
+
zones?: TaggedEntityRef[] | null;
|
|
61
|
+
floors?: TaggedEntityRef[] | null;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Inline tag projection returned when a Room/Zone/Floor query selects
|
|
65
|
+
* `tags { id name }` directly (e.g. `butlr_get_asset_details`).
|
|
66
|
+
*
|
|
67
|
+
* Lightweight `{id, name}` projection — both fields are required by
|
|
68
|
+
* the GraphQL schema and surfaced unchanged. Structurally similar to
|
|
69
|
+
* but intentionally distinct from `TaggedEntityRef`: `TaggedEntityRef`
|
|
70
|
+
* is best-effort (name optional) and represents the reverse direction
|
|
71
|
+
* (entities under a tag); `TagRef` represents tags applied to an
|
|
72
|
+
* entity. The bare name `Tag` is reserved for the full GraphQL Tag
|
|
73
|
+
* entity (with organization_id, associations, etc.); callers needing
|
|
74
|
+
* that shape go through `GET_TAGS_WITH_USAGE` instead.
|
|
75
|
+
*/
|
|
76
|
+
export interface TagRef {
|
|
77
|
+
id: string;
|
|
78
|
+
name: string;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* List every tag in the org along with its application footprint.
|
|
82
|
+
*
|
|
83
|
+
* Each tag's `rooms`, `zones`, and `floors` arrays carry both `id` and
|
|
84
|
+
* `name` so callers (e.g. `butlr_list_tags { include_entities: true }`,
|
|
85
|
+
* `butlr_list_topology { tag_names: [...] }`) can render the tagged
|
|
86
|
+
* entities without an extra resolution step.
|
|
87
|
+
*/
|
|
88
|
+
export declare const GET_TAGS_WITH_USAGE: import("@apollo/client").DocumentNode;
|
|
89
|
+
/**
|
|
90
|
+
* Minimal tag listing — id and name only.
|
|
91
|
+
*
|
|
92
|
+
* Used to resolve user-supplied tag names to tag IDs before invoking
|
|
93
|
+
* tag-filtered queries (e.g. `roomsByTag(tagIDs:..)`).
|
|
94
|
+
*/
|
|
95
|
+
export declare const GET_TAGS_MINIMAL: import("@apollo/client").DocumentNode;
|
|
96
|
+
//# sourceMappingURL=tags.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tags.d.ts","sourceRoot":"","sources":["../../../src/clients/queries/tags.ts"],"names":[],"mappings":"AAEA;;;;;;GAMG;AAEH;;;;;;;;GAQG;AACH,MAAM,MAAM,KAAK,GAAG,MAAM,GAAG;IAAE,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAAC;AAC3D,MAAM,MAAM,OAAO,GAAG,MAAM,GAAG;IAAE,QAAQ,CAAC,OAAO,EAAE,SAAS,CAAA;CAAE,CAAC;AAE/D,6EAA6E;AAC7E,MAAM,MAAM,QAAQ,GAAG,KAAK,GAAG,KAAK,CAAC;AAErC;;;;;GAKG;AACH,eAAO,MAAM,OAAO,GAAI,OAAO,MAAM,KAAG,KAKvC,CAAC;AAEF,yEAAyE;AACzE,eAAO,MAAM,SAAS,GAAI,OAAO,MAAM,KAAG,OAKzC,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,KAAK,CAAC,EAAE,eAAe,EAAE,GAAG,IAAI,CAAC;IACjC,KAAK,CAAC,EAAE,eAAe,EAAE,GAAG,IAAI,CAAC;IACjC,MAAM,CAAC,EAAE,eAAe,EAAE,GAAG,IAAI,CAAC;CACnC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,MAAM;IACrB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,mBAAmB,uCAoB/B,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,uCAO5B,CAAC"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { gql } from "@apollo/client";
|
|
2
|
+
/**
|
|
3
|
+
* Brand a string as a tag id. Throws on empty/whitespace-only input — the
|
|
4
|
+
* brand exists to catch "wrong slot" mistakes at compile time, but a blank
|
|
5
|
+
* value would brand cleanly and slip through. Constructors that accept
|
|
6
|
+
* arbitrary strings need a runtime check too.
|
|
7
|
+
*/
|
|
8
|
+
export const asTagId = (value) => {
|
|
9
|
+
if (typeof value !== "string" || value.trim().length === 0) {
|
|
10
|
+
throw new Error(`Invalid TagId: expected a non-empty string, got ${JSON.stringify(value)}`);
|
|
11
|
+
}
|
|
12
|
+
return value;
|
|
13
|
+
};
|
|
14
|
+
/** Brand a string as a tag name. Same empty-input guard as `asTagId`. */
|
|
15
|
+
export const asTagName = (value) => {
|
|
16
|
+
if (typeof value !== "string" || value.trim().length === 0) {
|
|
17
|
+
throw new Error(`Invalid TagName: expected a non-empty string, got ${JSON.stringify(value)}`);
|
|
18
|
+
}
|
|
19
|
+
return value;
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* List every tag in the org along with its application footprint.
|
|
23
|
+
*
|
|
24
|
+
* Each tag's `rooms`, `zones`, and `floors` arrays carry both `id` and
|
|
25
|
+
* `name` so callers (e.g. `butlr_list_tags { include_entities: true }`,
|
|
26
|
+
* `butlr_list_topology { tag_names: [...] }`) can render the tagged
|
|
27
|
+
* entities without an extra resolution step.
|
|
28
|
+
*/
|
|
29
|
+
export const GET_TAGS_WITH_USAGE = gql `
|
|
30
|
+
query GetTagsWithUsage {
|
|
31
|
+
tags {
|
|
32
|
+
id
|
|
33
|
+
name
|
|
34
|
+
organization_id
|
|
35
|
+
rooms {
|
|
36
|
+
id
|
|
37
|
+
name
|
|
38
|
+
}
|
|
39
|
+
zones {
|
|
40
|
+
id
|
|
41
|
+
name
|
|
42
|
+
}
|
|
43
|
+
floors {
|
|
44
|
+
id
|
|
45
|
+
name
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
`;
|
|
50
|
+
/**
|
|
51
|
+
* Minimal tag listing — id and name only.
|
|
52
|
+
*
|
|
53
|
+
* Used to resolve user-supplied tag names to tag IDs before invoking
|
|
54
|
+
* tag-filtered queries (e.g. `roomsByTag(tagIDs:..)`).
|
|
55
|
+
*/
|
|
56
|
+
export const GET_TAGS_MINIMAL = gql `
|
|
57
|
+
query GetTagsMinimal {
|
|
58
|
+
tags {
|
|
59
|
+
id
|
|
60
|
+
name
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
`;
|
|
64
|
+
//# sourceMappingURL=tags.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tags.js","sourceRoot":"","sources":["../../../src/clients/queries/tags.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,gBAAgB,CAAC;AAyBrC;;;;;GAKG;AACH,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,KAAa,EAAS,EAAE;IAC9C,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC3D,MAAM,IAAI,KAAK,CAAC,mDAAmD,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAC9F,CAAC;IACD,OAAO,KAAc,CAAC;AACxB,CAAC,CAAC;AAEF,yEAAyE;AACzE,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,KAAa,EAAW,EAAE;IAClD,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC3D,MAAM,IAAI,KAAK,CAAC,qDAAqD,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAChG,CAAC;IACD,OAAO,KAAgB,CAAC;AAC1B,CAAC,CAAC;AAmDF;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;CAoBrC,CAAC;AAEF;;;;;GAKG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,GAAG,CAAA;;;;;;;CAOlC,CAAC"}
|
package/dist/clients/types.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* TypeScript type definitions for Butlr GraphQL API
|
|
3
3
|
*/
|
|
4
|
+
import type { TagRef } from "./queries/tags.js";
|
|
4
5
|
export interface Capacity {
|
|
5
6
|
max?: number;
|
|
6
7
|
mid?: number;
|
|
@@ -24,7 +25,7 @@ export interface Area {
|
|
|
24
25
|
export interface Site {
|
|
25
26
|
id: string;
|
|
26
27
|
name: string;
|
|
27
|
-
timezone: string;
|
|
28
|
+
timezone: string | null;
|
|
28
29
|
org_id: string;
|
|
29
30
|
siteNumber?: number;
|
|
30
31
|
customID?: string;
|
|
@@ -55,7 +56,7 @@ export interface Floor {
|
|
|
55
56
|
name: string;
|
|
56
57
|
building_id: string;
|
|
57
58
|
floorNumber?: number;
|
|
58
|
-
timezone: string;
|
|
59
|
+
timezone: string | null;
|
|
59
60
|
installation_date: number;
|
|
60
61
|
installation_status?: string;
|
|
61
62
|
service_status?: string;
|
|
@@ -70,6 +71,7 @@ export interface Floor {
|
|
|
70
71
|
hives?: Hive[];
|
|
71
72
|
floor_plans?: FloorPlan[];
|
|
72
73
|
building: Building;
|
|
74
|
+
tags: TagRef[];
|
|
73
75
|
}
|
|
74
76
|
/**
|
|
75
77
|
* Room - Defined space within a floor
|
|
@@ -92,6 +94,7 @@ export interface Room {
|
|
|
92
94
|
pir_zero_window?: number;
|
|
93
95
|
sensors?: Sensor[];
|
|
94
96
|
floor: Floor;
|
|
97
|
+
tags: TagRef[];
|
|
95
98
|
}
|
|
96
99
|
/**
|
|
97
100
|
* Zone - Sub-area within a floor or room
|
|
@@ -111,6 +114,7 @@ export interface Zone {
|
|
|
111
114
|
customID?: string;
|
|
112
115
|
note?: string;
|
|
113
116
|
sensors?: Sensor[];
|
|
117
|
+
tags: TagRef[];
|
|
114
118
|
}
|
|
115
119
|
/**
|
|
116
120
|
* Sensor - Individual detection device
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/clients/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,WAAW,QAAQ;IACvB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,OAAO;IACtB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,QAAQ;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,IAAI;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;GAEG;AACH,MAAM,WAAW,IAAI;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/clients/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,6 +2,13 @@ import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
|
|
|
2
2
|
/**
|
|
3
3
|
* Wraps a tool handler to catch errors and return them as MCP tool errors
|
|
4
4
|
* with isError: true, so the LLM can see and handle the error.
|
|
5
|
+
*
|
|
6
|
+
* If the underlying error message already carries a `[CODE]` prefix
|
|
7
|
+
* (added by `formatMCPError` upstream), the message passes through. If
|
|
8
|
+
* it doesn't — non-Apollo Error classes, unrelated `throw new Error(...)`
|
|
9
|
+
* sites, ServerParseError, etc. — we wrap with an INTERNAL_ERROR prefix
|
|
10
|
+
* so consumers branching on `[XXX]` still see a structured code. Stack
|
|
11
|
+
* traces survive in the `debug` log but never reach the response body.
|
|
5
12
|
*/
|
|
6
13
|
export declare function withToolErrorHandling(handler: (args: Record<string, unknown>) => Promise<CallToolResult>): (args: Record<string, unknown>) => Promise<CallToolResult>;
|
|
7
14
|
/**
|
|
@@ -52,6 +59,33 @@ export declare function translateGraphQLError(error: GraphQLClientError): MCPErr
|
|
|
52
59
|
* Format MCP error for user-friendly display
|
|
53
60
|
*/
|
|
54
61
|
export declare function formatMCPError(error: MCPError): string;
|
|
62
|
+
/**
|
|
63
|
+
* Validate that an upstream-supplied value is array-shaped, returning the
|
|
64
|
+
* array (treating `null`/`undefined` as a legitimately-empty signal) or
|
|
65
|
+
* throwing INTERNAL_ERROR for any other shape. Centralizes the pattern
|
|
66
|
+
* that callers like `butlr_list_topology` / `butlr_list_tags` /
|
|
67
|
+
* `butlr_available_rooms` use on nested response fields where a
|
|
68
|
+
* `value || []` would otherwise launder a contract regression into
|
|
69
|
+
* silently-empty results.
|
|
70
|
+
*
|
|
71
|
+
* Pass `fieldName` for a useful error message; the lenient null/undefined
|
|
72
|
+
* branch reflects that legitimately-empty lists arrive as
|
|
73
|
+
* `[]`/`null`/missing depending on upstream resolver.
|
|
74
|
+
*/
|
|
75
|
+
export declare function ensureArrayOrEmpty<T>(value: ReadonlyArray<T> | null | undefined | unknown, fieldName: string): ReadonlyArray<T>;
|
|
76
|
+
/**
|
|
77
|
+
* Throw a properly MCP-formatted INTERNAL_ERROR. Use for upstream contract
|
|
78
|
+
* violations (unexpected response shape, missing data envelope, etc.) so
|
|
79
|
+
* the failure surfaces with a structured `[INTERNAL_ERROR]` prefix that
|
|
80
|
+
* `withToolErrorHandling` translates uniformly. Without this, every tool
|
|
81
|
+
* would have a different error-shape contract for the same class of bug.
|
|
82
|
+
*
|
|
83
|
+
* `retryable: false` — contract violations are not transient. If the
|
|
84
|
+
* upstream returned a non-array where an array was contracted, retrying
|
|
85
|
+
* will yield the same broken response. MCP clients that auto-retry
|
|
86
|
+
* `retryable: true` errors would spin against this signal otherwise.
|
|
87
|
+
*/
|
|
88
|
+
export declare function throwInternalError(message: string): never;
|
|
55
89
|
/**
|
|
56
90
|
* Error subclass for MCP errors — provides stack traces and works with instanceof checks.
|
|
57
91
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp-errors.d.ts","sourceRoot":"","sources":["../../src/errors/mcp-errors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AAGzE
|
|
1
|
+
{"version":3,"file":"mcp-errors.d.ts","sourceRoot":"","sources":["../../src/errors/mcp-errors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AAGzE;;;;;;;;;;GAUG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,cAAc,CAAC,GAClE,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,cAAc,CAAC,CAsB5D;AAED;;;GAGG;AACH,UAAU,kBAAkB;IAC1B,YAAY,CAAC,EAAE;QACb,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,MAAM,CAAC,EAAE,OAAO,CAAC;QACjB,QAAQ,CAAC,EAAE;YAAE,OAAO,CAAC,EAAE;gBAAE,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAA;aAAE,CAAA;SAAE,CAAC;KAC/D,CAAC;IACF,aAAa,CAAC,EAAE,KAAK,CAAC;QACpB,OAAO,EAAE,MAAM,CAAC;QAChB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KACtC,CAAC,CAAC;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;GAGG;AACH,oBAAY,YAAY;IACtB,YAAY,iBAAiB;IAC7B,YAAY,iBAAiB;IAC7B,iBAAiB,sBAAsB;IACvC,cAAc,mBAAmB;IACjC,SAAS,cAAc;IACvB,aAAa,kBAAkB;CAChC;AAED,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,YAAY,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,kBAAkB,GAAG,QAAQ,CA6GzE;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,QAAQ,GAAG,MAAM,CAgBtD;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,EAClC,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,EACpD,SAAS,EAAE,MAAM,GAChB,aAAa,CAAC,CAAC,CAAC,CAOlB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,KAAK,CAOzD;AAED;;GAEG;AACH,qBAAa,kBAAmB,SAAQ,KAAK;IAC3C,IAAI,EAAE,YAAY,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,SAAS,EAAE,OAAO,CAAC;gBAEP,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;CAO/D;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAChC,kBAAkB,CAEpB"}
|
|
@@ -2,6 +2,13 @@ import { debug } from "../utils/debug.js";
|
|
|
2
2
|
/**
|
|
3
3
|
* Wraps a tool handler to catch errors and return them as MCP tool errors
|
|
4
4
|
* with isError: true, so the LLM can see and handle the error.
|
|
5
|
+
*
|
|
6
|
+
* If the underlying error message already carries a `[CODE]` prefix
|
|
7
|
+
* (added by `formatMCPError` upstream), the message passes through. If
|
|
8
|
+
* it doesn't — non-Apollo Error classes, unrelated `throw new Error(...)`
|
|
9
|
+
* sites, ServerParseError, etc. — we wrap with an INTERNAL_ERROR prefix
|
|
10
|
+
* so consumers branching on `[XXX]` still see a structured code. Stack
|
|
11
|
+
* traces survive in the `debug` log but never reach the response body.
|
|
5
12
|
*/
|
|
6
13
|
export function withToolErrorHandling(handler) {
|
|
7
14
|
return async (args) => {
|
|
@@ -9,10 +16,19 @@ export function withToolErrorHandling(handler) {
|
|
|
9
16
|
return await handler(args);
|
|
10
17
|
}
|
|
11
18
|
catch (error) {
|
|
12
|
-
const
|
|
13
|
-
|
|
19
|
+
const rawMessage = error instanceof Error ? error.message : String(error);
|
|
20
|
+
const stack = error instanceof Error ? error.stack : undefined;
|
|
21
|
+
debug("tool-error", rawMessage, stack ?? error);
|
|
22
|
+
// Already-translated errors carry the `[CODE]` prefix; preserve them.
|
|
23
|
+
const text = /^\[[A-Z_]+\]/.test(rawMessage)
|
|
24
|
+
? rawMessage
|
|
25
|
+
: formatMCPError({
|
|
26
|
+
code: MCPErrorCode.INTERNAL_ERROR,
|
|
27
|
+
message: rawMessage || "Unknown internal error",
|
|
28
|
+
retryable: false,
|
|
29
|
+
});
|
|
14
30
|
return {
|
|
15
|
-
content: [{ type: "text", text
|
|
31
|
+
content: [{ type: "text", text }],
|
|
16
32
|
isError: true,
|
|
17
33
|
};
|
|
18
34
|
}
|
|
@@ -59,11 +75,20 @@ export function translateGraphQLError(error) {
|
|
|
59
75
|
retryAfter,
|
|
60
76
|
};
|
|
61
77
|
}
|
|
62
|
-
// Bad request / validation
|
|
78
|
+
// Bad request / validation. Surface the upstream message in the
|
|
79
|
+
// user-visible string so an LLM caller debugging a 400 doesn't have
|
|
80
|
+
// to wait for DEBUG=butlr-mcp to see "Unknown tag id: foo_bar". Fall
|
|
81
|
+
// back to the generic phrasing only when no message can be extracted.
|
|
63
82
|
if (networkError.statusCode === 400) {
|
|
83
|
+
const body = networkError.result;
|
|
84
|
+
const upstreamMessage = body?.errors?.find((e) => typeof e?.message === "string")?.message ??
|
|
85
|
+
(typeof networkError.message === "string" ? networkError.message : undefined);
|
|
86
|
+
const truncate = (s) => (s.length > 240 ? `${s.slice(0, 240)}…` : s);
|
|
64
87
|
return {
|
|
65
88
|
code: MCPErrorCode.VALIDATION_FAILED,
|
|
66
|
-
message:
|
|
89
|
+
message: upstreamMessage
|
|
90
|
+
? `Invalid request: ${truncate(String(upstreamMessage))}`
|
|
91
|
+
: "Invalid request parameters.",
|
|
67
92
|
details: {
|
|
68
93
|
statusCode: 400,
|
|
69
94
|
body: networkError.result,
|
|
@@ -140,6 +165,47 @@ export function formatMCPError(error) {
|
|
|
140
165
|
}
|
|
141
166
|
return message;
|
|
142
167
|
}
|
|
168
|
+
/**
|
|
169
|
+
* Validate that an upstream-supplied value is array-shaped, returning the
|
|
170
|
+
* array (treating `null`/`undefined` as a legitimately-empty signal) or
|
|
171
|
+
* throwing INTERNAL_ERROR for any other shape. Centralizes the pattern
|
|
172
|
+
* that callers like `butlr_list_topology` / `butlr_list_tags` /
|
|
173
|
+
* `butlr_available_rooms` use on nested response fields where a
|
|
174
|
+
* `value || []` would otherwise launder a contract regression into
|
|
175
|
+
* silently-empty results.
|
|
176
|
+
*
|
|
177
|
+
* Pass `fieldName` for a useful error message; the lenient null/undefined
|
|
178
|
+
* branch reflects that legitimately-empty lists arrive as
|
|
179
|
+
* `[]`/`null`/missing depending on upstream resolver.
|
|
180
|
+
*/
|
|
181
|
+
export function ensureArrayOrEmpty(value, fieldName) {
|
|
182
|
+
if (value === null || value === undefined)
|
|
183
|
+
return [];
|
|
184
|
+
if (Array.isArray(value))
|
|
185
|
+
return value;
|
|
186
|
+
throwInternalError(`Unexpected response shape from ${fieldName} (expected array, got ${typeof value}). ` +
|
|
187
|
+
"Please retry; if persistent, the upstream API contract may have changed.");
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Throw a properly MCP-formatted INTERNAL_ERROR. Use for upstream contract
|
|
191
|
+
* violations (unexpected response shape, missing data envelope, etc.) so
|
|
192
|
+
* the failure surfaces with a structured `[INTERNAL_ERROR]` prefix that
|
|
193
|
+
* `withToolErrorHandling` translates uniformly. Without this, every tool
|
|
194
|
+
* would have a different error-shape contract for the same class of bug.
|
|
195
|
+
*
|
|
196
|
+
* `retryable: false` — contract violations are not transient. If the
|
|
197
|
+
* upstream returned a non-array where an array was contracted, retrying
|
|
198
|
+
* will yield the same broken response. MCP clients that auto-retry
|
|
199
|
+
* `retryable: true` errors would spin against this signal otherwise.
|
|
200
|
+
*/
|
|
201
|
+
export function throwInternalError(message) {
|
|
202
|
+
const mcpError = {
|
|
203
|
+
code: MCPErrorCode.INTERNAL_ERROR,
|
|
204
|
+
message,
|
|
205
|
+
retryable: false,
|
|
206
|
+
};
|
|
207
|
+
throw new Error(formatMCPError(mcpError));
|
|
208
|
+
}
|
|
143
209
|
/**
|
|
144
210
|
* Error subclass for MCP errors — provides stack traces and works with instanceof checks.
|
|
145
211
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp-errors.js","sourceRoot":"","sources":["../../src/errors/mcp-errors.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAE1C
|
|
1
|
+
{"version":3,"file":"mcp-errors.js","sourceRoot":"","sources":["../../src/errors/mcp-errors.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAE1C;;;;;;;;;;GAUG;AACH,MAAM,UAAU,qBAAqB,CACnC,OAAmE;IAEnE,OAAO,KAAK,EAAE,IAAI,EAAE,EAAE;QACpB,IAAI,CAAC;YACH,OAAO,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;QAC7B,CAAC;QAAC,OAAO,KAAc,EAAE,CAAC;YACxB,MAAM,UAAU,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YAC1E,MAAM,KAAK,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;YAC/D,KAAK,CAAC,YAAY,EAAE,UAAU,EAAE,KAAK,IAAI,KAAK,CAAC,CAAC;YAChD,sEAAsE;YACtE,MAAM,IAAI,GAAG,cAAc,CAAC,IAAI,CAAC,UAAU,CAAC;gBAC1C,CAAC,CAAC,UAAU;gBACZ,CAAC,CAAC,cAAc,CAAC;oBACb,IAAI,EAAE,YAAY,CAAC,cAAc;oBACjC,OAAO,EAAE,UAAU,IAAI,wBAAwB;oBAC/C,SAAS,EAAE,KAAK;iBACjB,CAAC,CAAC;YACP,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,CAAC;gBAC1C,OAAO,EAAE,IAAI;aACd,CAAC;QACJ,CAAC;IACH,CAAC,CAAC;AACJ,CAAC;AAoBD;;;GAGG;AACH,MAAM,CAAN,IAAY,YAOX;AAPD,WAAY,YAAY;IACtB,6CAA6B,CAAA;IAC7B,6CAA6B,CAAA;IAC7B,uDAAuC,CAAA;IACvC,iDAAiC,CAAA;IACjC,uCAAuB,CAAA;IACvB,+CAA+B,CAAA;AACjC,CAAC,EAPW,YAAY,KAAZ,YAAY,QAOvB;AAUD;;GAEG;AACH,MAAM,UAAU,qBAAqB,CAAC,KAAyB;IAC7D,2BAA2B;IAC3B,IAAI,KAAK,CAAC,YAAY,EAAE,CAAC;QACvB,MAAM,YAAY,GAAG,KAAK,CAAC,YAAY,CAAC;QAExC,wBAAwB;QACxB,IAAI,YAAY,CAAC,UAAU,KAAK,GAAG,IAAI,YAAY,CAAC,UAAU,KAAK,GAAG,EAAE,CAAC;YACvE,OAAO;gBACL,IAAI,EAAE,YAAY,CAAC,YAAY;gBAC/B,OAAO,EAAE,8EAA8E;gBACvF,OAAO,EAAE;oBACP,UAAU,EAAE,YAAY,CAAC,UAAU;iBACpC;gBACD,SAAS,EAAE,KAAK;aACjB,CAAC;QACJ,CAAC;QAED,gBAAgB;QAChB,IAAI,YAAY,CAAC,UAAU,KAAK,GAAG,EAAE,CAAC;YACpC,MAAM,UAAU,GAAG,QAAQ,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,CAAC,aAAa,CAAC,IAAI,IAAI,EAAE,EAAE,CAAC,CAAC;YAC5F,OAAO;gBACL,IAAI,EAAE,YAAY,CAAC,YAAY;gBAC/B,OAAO,EAAE,+CAA+C,UAAU,WAAW;gBAC7E,SAAS,EAAE,IAAI;gBACf,UAAU;aACX,CAAC;QACJ,CAAC;QAED,gEAAgE;QAChE,oEAAoE;QACpE,qEAAqE;QACrE,sEAAsE;QACtE,IAAI,YAAY,CAAC,UAAU,KAAK,GAAG,EAAE,CAAC;YACpC,MAAM,IAAI,GAAG,YAAY,CAAC,MAA+D,CAAC;YAC1F,MAAM,eAAe,GACnB,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,EAAE,OAAO,KAAK,QAAQ,CAAC,EAAE,OAAO;gBAClE,CAAC,OAAO,YAAY,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;YAChF,MAAM,QAAQ,GAAG,CAAC,CAAS,EAAU,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YACrF,OAAO;gBACL,IAAI,EAAE,YAAY,CAAC,iBAAiB;gBACpC,OAAO,EAAE,eAAe;oBACtB,CAAC,CAAC,oBAAoB,QAAQ,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,EAAE;oBACzD,CAAC,CAAC,6BAA6B;gBACjC,OAAO,EAAE;oBACP,UAAU,EAAE,GAAG;oBACf,IAAI,EAAE,YAAY,CAAC,MAAM;iBAC1B;gBACD,SAAS,EAAE,KAAK;aACjB,CAAC;QACJ,CAAC;QAED,YAAY;QACZ,IAAI,YAAY,CAAC,UAAU,KAAK,GAAG,EAAE,CAAC;YACpC,OAAO;gBACL,IAAI,EAAE,YAAY,CAAC,SAAS;gBAC5B,OAAO,EAAE,qBAAqB;gBAC9B,SAAS,EAAE,KAAK;aACjB,CAAC;QACJ,CAAC;QAED,wBAAwB;QACxB,OAAO;YACL,IAAI,EAAE,YAAY,CAAC,aAAa;YAChC,OAAO,EAAE,kBAAkB,YAAY,CAAC,OAAO,EAAE;YACjD,OAAO,EAAE;gBACP,UAAU,EAAE,YAAY,CAAC,UAAU;aACpC;YACD,SAAS,EAAE,IAAI;SAChB,CAAC;IACJ,CAAC;IAED,2BAA2B;IAC3B,IAAI,KAAK,CAAC,aAAa,IAAI,KAAK,CAAC,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC1D,MAAM,UAAU,GAAG,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;QAE1C,wBAAwB;QACxB,IAAI,UAAU,CAAC,UAAU,EAAE,IAAI,KAAK,iBAAiB,EAAE,CAAC;YACtD,OAAO;gBACL,IAAI,EAAE,YAAY,CAAC,YAAY;gBAC/B,OAAO,EAAE,oDAAoD;gBAC7D,SAAS,EAAE,IAAI;aAChB,CAAC;QACJ,CAAC;QAED,oBAAoB;QACpB,IAAI,UAAU,CAAC,UAAU,EAAE,IAAI,KAAK,gBAAgB,EAAE,CAAC;YACrD,OAAO;gBACL,IAAI,EAAE,YAAY,CAAC,iBAAiB;gBACpC,OAAO,EAAE,kBAAkB,UAAU,CAAC,OAAO,EAAE;gBAC/C,OAAO,EAAE,UAAU,CAAC,UAAU;gBAC9B,SAAS,EAAE,KAAK;aACjB,CAAC;QACJ,CAAC;QAED,wBAAwB;QACxB,OAAO;YACL,IAAI,EAAE,YAAY,CAAC,cAAc;YACjC,OAAO,EAAE,UAAU,CAAC,OAAO;YAC3B,OAAO,EAAE,UAAU,CAAC,UAAU;YAC9B,SAAS,EAAE,KAAK;SACjB,CAAC;IACJ,CAAC;IAED,0BAA0B;IAC1B,OAAO;QACL,IAAI,EAAE,YAAY,CAAC,cAAc;QACjC,OAAO,EAAE,KAAK,CAAC,OAAO,IAAI,2BAA2B;QACrD,SAAS,EAAE,KAAK;KACjB,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,cAAc,CAAC,KAAe;IAC5C,IAAI,OAAO,GAAG,IAAI,KAAK,CAAC,IAAI,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC;IAEjD,IAAI,KAAK,CAAC,SAAS,EAAE,CAAC;QACpB,OAAO,IAAI,cAAc,CAAC;IAC5B,CAAC;IAED,IAAI,KAAK,CAAC,UAAU,EAAE,CAAC;QACrB,OAAO,IAAI,kBAAkB,KAAK,CAAC,UAAU,GAAG,CAAC;IACnD,CAAC;IAED,IAAI,KAAK,CAAC,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,KAAK,WAAW,IAAI,OAAO,CAAC,GAAG,CAAC,KAAK,KAAK,GAAG,CAAC,EAAE,CAAC;QACtF,OAAO,IAAI,cAAc,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;IACpE,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,kBAAkB,CAChC,KAAoD,EACpD,SAAiB;IAEjB,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,EAAE,CAAC;IACrD,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,KAAyB,CAAC;IAC3D,kBAAkB,CAChB,kCAAkC,SAAS,yBAAyB,OAAO,KAAK,KAAK;QACnF,0EAA0E,CAC7E,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,kBAAkB,CAAC,OAAe;IAChD,MAAM,QAAQ,GAAa;QACzB,IAAI,EAAE,YAAY,CAAC,cAAc;QACjC,OAAO;QACP,SAAS,EAAE,KAAK;KACjB,CAAC;IACF,MAAM,IAAI,KAAK,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC,CAAC;AAC5C,CAAC;AAED;;GAEG;AACH,MAAM,OAAO,kBAAmB,SAAQ,KAAK;IAC3C,IAAI,CAAe;IACnB,OAAO,CAA2B;IAClC,SAAS,CAAU;IAEnB,YAAY,OAAe,EAAE,OAAiC;QAC5D,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,oBAAoB,CAAC;QACjC,IAAI,CAAC,IAAI,GAAG,YAAY,CAAC,iBAAiB,CAAC;QAC3C,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC;IACzB,CAAC;CACF;AAED;;GAEG;AACH,MAAM,UAAU,qBAAqB,CACnC,OAAe,EACf,OAAiC;IAEjC,OAAO,IAAI,kBAAkB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;AAClD,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -12,6 +12,7 @@ import { registerListTopology } from "./tools/butlr-list-topology.js";
|
|
|
12
12
|
import { registerFetchEntityDetails } from "./tools/butlr-fetch-entity-details.js";
|
|
13
13
|
import { registerGetOccupancyTimeseries } from "./tools/butlr-get-occupancy-timeseries.js";
|
|
14
14
|
import { registerGetCurrentOccupancy } from "./tools/butlr-get-current-occupancy.js";
|
|
15
|
+
import { registerListTags } from "./tools/butlr-list-tags.js";
|
|
15
16
|
import { debug } from "./utils/debug.js";
|
|
16
17
|
const require = createRequire(import.meta.url);
|
|
17
18
|
const { version: SERVER_VERSION } = require("../package.json");
|
|
@@ -31,6 +32,7 @@ registerListTopology(server);
|
|
|
31
32
|
registerFetchEntityDetails(server);
|
|
32
33
|
registerGetOccupancyTimeseries(server);
|
|
33
34
|
registerGetCurrentOccupancy(server);
|
|
35
|
+
registerListTags(server);
|
|
34
36
|
async function main() {
|
|
35
37
|
const transport = new StdioServerTransport();
|
|
36
38
|
await server.connect(transport);
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,oBAAoB,EAAE,MAAM,gCAAgC,CAAC;AACtE,OAAO,EAAE,uBAAuB,EAAE,MAAM,oCAAoC,CAAC;AAC7E,OAAO,EAAE,wBAAwB,EAAE,MAAM,oCAAoC,CAAC;AAC9E,OAAO,EAAE,sBAAsB,EAAE,MAAM,kCAAkC,CAAC;AAC1E,OAAO,EAAE,qBAAqB,EAAE,MAAM,iCAAiC,CAAC;AACxE,OAAO,EAAE,mBAAmB,EAAE,MAAM,+BAA+B,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,gCAAgC,CAAC;AACtE,OAAO,EAAE,0BAA0B,EAAE,MAAM,uCAAuC,CAAC;AACnF,OAAO,EAAE,8BAA8B,EAAE,MAAM,2CAA2C,CAAC;AAC3F,OAAO,EAAE,2BAA2B,EAAE,MAAM,wCAAwC,CAAC;AACrF,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAEzC,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC/C,MAAM,EAAE,OAAO,EAAE,cAAc,EAAE,GAAG,OAAO,CAAC,iBAAiB,CAAwB,CAAC;AAEtF,MAAM,WAAW,GAAG,kBAAkB,CAAC;AAEvC,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;IAC3B,IAAI,EAAE,WAAW;IACjB,OAAO,EAAE,cAAc;CACxB,CAAC,CAAC;AAEH,qBAAqB;AACrB,oBAAoB,CAAC,MAAM,CAAC,CAAC;AAC7B,uBAAuB,CAAC,MAAM,CAAC,CAAC;AAChC,wBAAwB,CAAC,MAAM,CAAC,CAAC;AACjC,sBAAsB,CAAC,MAAM,CAAC,CAAC;AAC/B,qBAAqB,CAAC,MAAM,CAAC,CAAC;AAC9B,mBAAmB,CAAC,MAAM,CAAC,CAAC;AAC5B,oBAAoB,CAAC,MAAM,CAAC,CAAC;AAC7B,0BAA0B,CAAC,MAAM,CAAC,CAAC;AACnC,8BAA8B,CAAC,MAAM,CAAC,CAAC;AACvC,2BAA2B,CAAC,MAAM,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,oBAAoB,EAAE,MAAM,gCAAgC,CAAC;AACtE,OAAO,EAAE,uBAAuB,EAAE,MAAM,oCAAoC,CAAC;AAC7E,OAAO,EAAE,wBAAwB,EAAE,MAAM,oCAAoC,CAAC;AAC9E,OAAO,EAAE,sBAAsB,EAAE,MAAM,kCAAkC,CAAC;AAC1E,OAAO,EAAE,qBAAqB,EAAE,MAAM,iCAAiC,CAAC;AACxE,OAAO,EAAE,mBAAmB,EAAE,MAAM,+BAA+B,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,gCAAgC,CAAC;AACtE,OAAO,EAAE,0BAA0B,EAAE,MAAM,uCAAuC,CAAC;AACnF,OAAO,EAAE,8BAA8B,EAAE,MAAM,2CAA2C,CAAC;AAC3F,OAAO,EAAE,2BAA2B,EAAE,MAAM,wCAAwC,CAAC;AACrF,OAAO,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAC9D,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAEzC,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC/C,MAAM,EAAE,OAAO,EAAE,cAAc,EAAE,GAAG,OAAO,CAAC,iBAAiB,CAAwB,CAAC;AAEtF,MAAM,WAAW,GAAG,kBAAkB,CAAC;AAEvC,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;IAC3B,IAAI,EAAE,WAAW;IACjB,OAAO,EAAE,cAAc;CACxB,CAAC,CAAC;AAEH,qBAAqB;AACrB,oBAAoB,CAAC,MAAM,CAAC,CAAC;AAC7B,uBAAuB,CAAC,MAAM,CAAC,CAAC;AAChC,wBAAwB,CAAC,MAAM,CAAC,CAAC;AACjC,sBAAsB,CAAC,MAAM,CAAC,CAAC;AAC/B,qBAAqB,CAAC,MAAM,CAAC,CAAC;AAC9B,mBAAmB,CAAC,MAAM,CAAC,CAAC;AAC5B,oBAAoB,CAAC,MAAM,CAAC,CAAC;AAC7B,0BAA0B,CAAC,MAAM,CAAC,CAAC;AACnC,8BAA8B,CAAC,MAAM,CAAC,CAAC;AACvC,2BAA2B,CAAC,MAAM,CAAC,CAAC;AACpC,gBAAgB,CAAC,MAAM,CAAC,CAAC;AAEzB,KAAK,UAAU,IAAI;IACjB,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAEhC,KAAK,CAAC,WAAW,EAAE,mCAAmC,CAAC,CAAC;IACxD,KAAK,CAAC,WAAW,EAAE,YAAY,cAAc,EAAE,CAAC,CAAC;AACnD,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IACrB,OAAO,CAAC,KAAK,CAAC,eAAe,EAAE,KAAK,CAAC,CAAC;IACtC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|