@commandable/mcp-core 0.2.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/LICENSE +10 -0
- package/README.md +8 -0
- package/dist/config/configApply.d.ts +16 -0
- package/dist/config/configApply.d.ts.map +1 -0
- package/dist/config/configApply.js +77 -0
- package/dist/config/configApply.js.map +1 -0
- package/dist/config/configLoader.d.ts +9 -0
- package/dist/config/configLoader.d.ts.map +1 -0
- package/dist/config/configLoader.js +75 -0
- package/dist/config/configLoader.js.map +1 -0
- package/dist/config/configSchema.d.ts +45 -0
- package/dist/config/configSchema.d.ts.map +1 -0
- package/dist/config/configSchema.js +23 -0
- package/dist/config/configSchema.js.map +1 -0
- package/dist/crypto/encryption.d.ts +3 -0
- package/dist/crypto/encryption.d.ts.map +1 -0
- package/dist/crypto/encryption.js +29 -0
- package/dist/crypto/encryption.js.map +1 -0
- package/dist/db/client.d.ts +24 -0
- package/dist/db/client.d.ts.map +1 -0
- package/dist/db/client.js +50 -0
- package/dist/db/client.js.map +1 -0
- package/dist/db/credentialStore.d.ts +15 -0
- package/dist/db/credentialStore.d.ts.map +1 -0
- package/dist/db/credentialStore.js +56 -0
- package/dist/db/credentialStore.js.map +1 -0
- package/dist/db/integrationStore.d.ts +14 -0
- package/dist/db/integrationStore.d.ts.map +1 -0
- package/dist/db/integrationStore.js +128 -0
- package/dist/db/integrationStore.js.map +1 -0
- package/dist/db/integrationTypeConfigStore.d.ts +7 -0
- package/dist/db/integrationTypeConfigStore.d.ts.map +1 -0
- package/dist/db/integrationTypeConfigStore.js +101 -0
- package/dist/db/integrationTypeConfigStore.js.map +1 -0
- package/dist/db/migrate.d.ts +3 -0
- package/dist/db/migrate.d.ts.map +1 -0
- package/dist/db/migrate.js +11 -0
- package/dist/db/migrate.js.map +1 -0
- package/dist/db/migrations/pg/0000_initial.sql +74 -0
- package/dist/db/migrations/pg/meta/_journal.json +13 -0
- package/dist/db/migrations/sqlite/0000_initial.sql +74 -0
- package/dist/db/migrations/sqlite/meta/_journal.json +13 -0
- package/dist/db/schema.d.ts +1863 -0
- package/dist/db/schema.d.ts.map +1 -0
- package/dist/db/schema.js +133 -0
- package/dist/db/schema.js.map +1 -0
- package/dist/db/toolDefinitionStore.d.ts +9 -0
- package/dist/db/toolDefinitionStore.d.ts.map +1 -0
- package/dist/db/toolDefinitionStore.js +117 -0
- package/dist/db/toolDefinitionStore.js.map +1 -0
- package/dist/errors/httpError.d.ts +6 -0
- package/dist/errors/httpError.d.ts.map +1 -0
- package/dist/errors/httpError.js +11 -0
- package/dist/errors/httpError.js.map +1 -0
- package/dist/index.d.ts +34 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +34 -0
- package/dist/index.js.map +1 -0
- package/dist/integrations/actionsFactory.d.ts +16 -0
- package/dist/integrations/actionsFactory.d.ts.map +1 -0
- package/dist/integrations/actionsFactory.js +98 -0
- package/dist/integrations/actionsFactory.js.map +1 -0
- package/dist/integrations/catalog.d.ts +8 -0
- package/dist/integrations/catalog.d.ts.map +1 -0
- package/dist/integrations/catalog.js +45 -0
- package/dist/integrations/catalog.js.map +1 -0
- package/dist/integrations/customToolFactory.d.ts +13 -0
- package/dist/integrations/customToolFactory.d.ts.map +1 -0
- package/dist/integrations/customToolFactory.js +31 -0
- package/dist/integrations/customToolFactory.js.map +1 -0
- package/dist/integrations/dataLoader.d.ts +3 -0
- package/dist/integrations/dataLoader.d.ts.map +1 -0
- package/dist/integrations/dataLoader.js +2 -0
- package/dist/integrations/dataLoader.js.map +1 -0
- package/dist/integrations/fileIntegrationTypeConfigStore.d.ts +7 -0
- package/dist/integrations/fileIntegrationTypeConfigStore.d.ts.map +1 -0
- package/dist/integrations/fileIntegrationTypeConfigStore.js +34 -0
- package/dist/integrations/fileIntegrationTypeConfigStore.js.map +1 -0
- package/dist/integrations/getIntegration.d.ts +14 -0
- package/dist/integrations/getIntegration.d.ts.map +1 -0
- package/dist/integrations/getIntegration.js +30 -0
- package/dist/integrations/getIntegration.js.map +1 -0
- package/dist/integrations/googleServiceAccount.d.ts +6 -0
- package/dist/integrations/googleServiceAccount.d.ts.map +1 -0
- package/dist/integrations/googleServiceAccount.js +54 -0
- package/dist/integrations/googleServiceAccount.js.map +1 -0
- package/dist/integrations/health.d.ts +20 -0
- package/dist/integrations/health.d.ts.map +1 -0
- package/dist/integrations/health.js +43 -0
- package/dist/integrations/health.js.map +1 -0
- package/dist/integrations/integrationTypeConfigLookup.d.ts +12 -0
- package/dist/integrations/integrationTypeConfigLookup.d.ts.map +1 -0
- package/dist/integrations/integrationTypeConfigLookup.js +11 -0
- package/dist/integrations/integrationTypeConfigLookup.js.map +1 -0
- package/dist/integrations/providerRegistry.d.ts +2 -0
- package/dist/integrations/providerRegistry.d.ts.map +1 -0
- package/dist/integrations/providerRegistry.js +72 -0
- package/dist/integrations/providerRegistry.js.map +1 -0
- package/dist/integrations/proxy.d.ts +19 -0
- package/dist/integrations/proxy.d.ts.map +1 -0
- package/dist/integrations/proxy.js +377 -0
- package/dist/integrations/proxy.js.map +1 -0
- package/dist/integrations/sandbox.d.ts +8 -0
- package/dist/integrations/sandbox.d.ts.map +1 -0
- package/dist/integrations/sandbox.js +221 -0
- package/dist/integrations/sandbox.js.map +1 -0
- package/dist/integrations/sandboxUtils.d.ts +15 -0
- package/dist/integrations/sandboxUtils.d.ts.map +1 -0
- package/dist/integrations/sandboxUtils.js +489 -0
- package/dist/integrations/sandboxUtils.js.map +1 -0
- package/dist/integrations/tools.d.ts +3 -0
- package/dist/integrations/tools.d.ts.map +1 -0
- package/dist/integrations/tools.js +70 -0
- package/dist/integrations/tools.js.map +1 -0
- package/dist/mcp/abilityCatalog.d.ts +51 -0
- package/dist/mcp/abilityCatalog.d.ts.map +1 -0
- package/dist/mcp/abilityCatalog.js +300 -0
- package/dist/mcp/abilityCatalog.js.map +1 -0
- package/dist/mcp/auth.d.ts +18 -0
- package/dist/mcp/auth.d.ts.map +1 -0
- package/dist/mcp/auth.js +45 -0
- package/dist/mcp/auth.js.map +1 -0
- package/dist/mcp/builder_guide.md +441 -0
- package/dist/mcp/commandable_readme.md +29 -0
- package/dist/mcp/handlers.d.ts +21 -0
- package/dist/mcp/handlers.d.ts.map +1 -0
- package/dist/mcp/handlers.js +86 -0
- package/dist/mcp/handlers.js.map +1 -0
- package/dist/mcp/metaTools.d.ts +79 -0
- package/dist/mcp/metaTools.d.ts.map +1 -0
- package/dist/mcp/metaTools.js +901 -0
- package/dist/mcp/metaTools.js.map +1 -0
- package/dist/mcp/server.d.ts +25 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +14 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/sessionState.d.ts +19 -0
- package/dist/mcp/sessionState.d.ts.map +1 -0
- package/dist/mcp/sessionState.js +79 -0
- package/dist/mcp/sessionState.js.map +1 -0
- package/dist/mcp/toolAdapter.d.ts +34 -0
- package/dist/mcp/toolAdapter.d.ts.map +1 -0
- package/dist/mcp/toolAdapter.js +24 -0
- package/dist/mcp/toolAdapter.js.map +1 -0
- package/dist/runtime/credentialManager.d.ts +19 -0
- package/dist/runtime/credentialManager.d.ts.map +1 -0
- package/dist/runtime/credentialManager.js +82 -0
- package/dist/runtime/credentialManager.js.map +1 -0
- package/dist/runtime/stdioSession.d.ts +8 -0
- package/dist/runtime/stdioSession.d.ts.map +1 -0
- package/dist/runtime/stdioSession.js +79 -0
- package/dist/runtime/stdioSession.js.map +1 -0
- package/dist/types.d.ts +92 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +64 -0
|
@@ -0,0 +1,441 @@
|
|
|
1
|
+
# Commandable Builder — vibe-coding new tools
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
You now have the tools to create **new custom tools** against any connected integration.
|
|
6
|
+
|
|
7
|
+
Each custom tool you create is:
|
|
8
|
+
|
|
9
|
+
- persisted to the Commandable database
|
|
10
|
+
- registered into the current session immediately (you can call it right away)
|
|
11
|
+
- available in `commandable_search_tools` for future sessions
|
|
12
|
+
|
|
13
|
+
Your job is to write four things for each tool:
|
|
14
|
+
|
|
15
|
+
- a **name** — the stable snake_case identifier (e.g. `list_sprint_tickets`)
|
|
16
|
+
- a **description** — one sentence, what it does and when to use it
|
|
17
|
+
- an **input schema** — a JSON Schema object that defines the arguments the caller passes
|
|
18
|
+
- **handler code** — raw JavaScript that calls the integration and returns data
|
|
19
|
+
|
|
20
|
+
When you're done with a tool, call `commandable_upsert_custom_tool`. It persists (or updates) the tool and triggers a live `tools/list_changed` notification — the tool is callable immediately.
|
|
21
|
+
|
|
22
|
+
## Creating brand new integrations (full vibe-coded integrations)
|
|
23
|
+
|
|
24
|
+
If the user needs an API that isn't connected yet, you can create a brand new integration type from scratch using:
|
|
25
|
+
|
|
26
|
+
- `commandable_upsert_custom_integration`
|
|
27
|
+
|
|
28
|
+
This creates:
|
|
29
|
+
|
|
30
|
+
- a new **integration type slug** (auto-generated like `stripe-a3f2`)
|
|
31
|
+
- a new **integration instance** (with an `integration_id`)
|
|
32
|
+
- a **credential form schema** (so the user can enter credentials out-of-band)
|
|
33
|
+
- an **auth injection rule** (so Commandable injects credentials into API calls)
|
|
34
|
+
|
|
35
|
+
After creation, the user must open the returned `credential_url` and enter credentials. Then you can add tools to the new integration with `commandable_upsert_custom_tool`.
|
|
36
|
+
|
|
37
|
+
### `commandable_upsert_custom_integration` inputs
|
|
38
|
+
|
|
39
|
+
- **`label`**: display name, e.g. `"Stripe"`
|
|
40
|
+
- **`base_url`**: API base URL, e.g. `"https://api.stripe.com/v1"`
|
|
41
|
+
- **`auth_type`**: `"custom"` or `"basic"`
|
|
42
|
+
- **`credential_fields`**: fields the user will enter (name + label, optional description)
|
|
43
|
+
- **`credential_injection`** (required for `auth_type: "custom"`): headers/query templates using `{{fieldName}}`
|
|
44
|
+
- **`basic_username_field` / `basic_password_field`** (required for `auth_type: "basic"`): which credential fields map to username/password
|
|
45
|
+
- **`connection_hint`**: markdown shown in the credential form. **Always include this.** Write it as a numbered list of every step the user must follow to obtain the credentials — starting from opening the right website, navigating to the correct settings page, creating or copying the token/key/secret, and pasting it into the field. Leave nothing implicit. See the Stripe example below.
|
|
46
|
+
|
|
47
|
+
#### Auth types
|
|
48
|
+
|
|
49
|
+
| `auth_type` | When to use | How it works |
|
|
50
|
+
|---|---|---|
|
|
51
|
+
| `custom` | Bearer tokens, API keys, custom headers/query params | You provide template strings like `Authorization: Bearer {{apiKey}}` and Commandable injects them |
|
|
52
|
+
| `basic` | APIs that use HTTP Basic Auth | Commandable base64 encodes `username:password` from the mapped credential fields and injects `Authorization: Basic <token>` |
|
|
53
|
+
|
|
54
|
+
#### Template expressions in `credential_injection`
|
|
55
|
+
|
|
56
|
+
Inside `custom` injection templates you can use more than just plain `{{fieldName}}` references. The following expressions are supported:
|
|
57
|
+
|
|
58
|
+
| Expression | What it produces |
|
|
59
|
+
|---|---|
|
|
60
|
+
| `{{fieldName}}` | The raw value of that credential field |
|
|
61
|
+
| `{{base64(expr)}}` | Base64-encodes the result of `expr`. `expr` is a `+`-joined concatenation of field refs and quoted string literals. |
|
|
62
|
+
|
|
63
|
+
**Example — Atlassian API token (email + token combined into Basic auth):**
|
|
64
|
+
|
|
65
|
+
```json
|
|
66
|
+
"credential_injection": {
|
|
67
|
+
"headers": {
|
|
68
|
+
"Authorization": "Basic {{base64(email + \":\" + apiToken)}}",
|
|
69
|
+
"Accept": "application/json"
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Use this pattern whenever an API takes a `username:password` style Basic auth but exposes them as two separate credential fields. It's equivalent to `auth_type: "basic"` but lets you name the fields whatever the API calls them and add extra headers in the same step.
|
|
75
|
+
|
|
76
|
+
## The mental model
|
|
77
|
+
|
|
78
|
+
Think of each tool as a tiny, focused action. One API call, one clear purpose.
|
|
79
|
+
|
|
80
|
+
The best tools are:
|
|
81
|
+
|
|
82
|
+
- **small** — one endpoint, one responsibility
|
|
83
|
+
- **reliable** — GET tools that return IDs + names so write tools always have correct input
|
|
84
|
+
- **easy to call** — input schema matches how a human would naturally describe what they want
|
|
85
|
+
- **honest** — `console.log` lines tell the user what's happening in plain English
|
|
86
|
+
|
|
87
|
+
The typical pattern is: build a `list_*` or `get_*` read tool first to discover IDs and field structure, then build the write tool that uses those IDs. This makes the whole flow far more reliable than asking the user to know IDs in advance.
|
|
88
|
+
|
|
89
|
+
## What is available in handler code
|
|
90
|
+
|
|
91
|
+
Handler code runs in a **sandboxed Node.js VM**. There is no internet access, no file system, no native packages.
|
|
92
|
+
|
|
93
|
+
### Available globals
|
|
94
|
+
|
|
95
|
+
| Global | What it is |
|
|
96
|
+
|---|---|
|
|
97
|
+
| `integration` | The connected integration client for this tool (see below) |
|
|
98
|
+
| `console.log(...)` | User-facing log messages (friendly, not technical) |
|
|
99
|
+
| `URL` | For safe URL construction |
|
|
100
|
+
| `URLSearchParams` | For building query strings |
|
|
101
|
+
| `atob` / `btoa` | Base64 encode/decode |
|
|
102
|
+
| `encodeURIComponent` / `decodeURIComponent` | URL encoding helpers |
|
|
103
|
+
|
|
104
|
+
### Blocked (not available)
|
|
105
|
+
|
|
106
|
+
`fetch`, `axios`, `process`, `require`, `Buffer`, `global`, `globalThis`, `setTimeout`, `setInterval`, `eval`, `Function`
|
|
107
|
+
|
|
108
|
+
If you need to call an API, use `integration.*`. There is no other way.
|
|
109
|
+
|
|
110
|
+
### The `integration` object
|
|
111
|
+
|
|
112
|
+
`integration` is the pre-authenticated client for this tool's integration instance. Commandable injects credentials automatically — the handler never touches secrets.
|
|
113
|
+
|
|
114
|
+
```js
|
|
115
|
+
integration.fetch(path, init?) // → Response (standard Fetch Response)
|
|
116
|
+
integration.get(path, init?) // GET shorthand
|
|
117
|
+
integration.post(path, body, init?) // POST shorthand
|
|
118
|
+
integration.put(path, body, init?) // PUT shorthand
|
|
119
|
+
integration.patch(path, body, init?) // PATCH shorthand
|
|
120
|
+
integration.delete(path, init?) // DELETE shorthand
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
All paths are **relative to the integration's base URL**. So if the base is `https://api.github.com`, write `/repos/owner/repo/issues` — not the full URL.
|
|
124
|
+
|
|
125
|
+
`integration.fetch` and all verb shorthands return a standard Fetch `Response`. Always do `await res.json()` or `await res.text()` to read the body.
|
|
126
|
+
|
|
127
|
+
## Handler code rules (strict)
|
|
128
|
+
|
|
129
|
+
Handler code **must**:
|
|
130
|
+
|
|
131
|
+
1. Be a raw JavaScript expression — **no TypeScript**, no `import`, no `require`
|
|
132
|
+
2. Start with `async (input) => {`
|
|
133
|
+
3. Use `input.*` for any parameters (they're validated by your input schema before the handler runs — no need to check them)
|
|
134
|
+
4. Return something meaningful — small JSON objects are easiest for the agent to reason with
|
|
135
|
+
|
|
136
|
+
```js
|
|
137
|
+
async (input) => {
|
|
138
|
+
const res = await integration.fetch(`/some/path/${input.id}`)
|
|
139
|
+
const data = await res.json()
|
|
140
|
+
console.log('Fetched item:', data.name)
|
|
141
|
+
return { id: data.id, name: data.name }
|
|
142
|
+
}
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
## Input schema rules
|
|
146
|
+
|
|
147
|
+
`input_schema` is a **JSON Schema object** (not a string).
|
|
148
|
+
|
|
149
|
+
- Use `type: "object"` at the top level
|
|
150
|
+
- Set `additionalProperties: false` — keeps calls clean
|
|
151
|
+
- List every field the handler actually reads in `properties`
|
|
152
|
+
- Put required fields in `required`
|
|
153
|
+
- Keep types simple — `string`, `number`, `boolean`, `array`, `object`
|
|
154
|
+
|
|
155
|
+
```json
|
|
156
|
+
{
|
|
157
|
+
"type": "object",
|
|
158
|
+
"properties": {
|
|
159
|
+
"owner": { "type": "string" },
|
|
160
|
+
"repo": { "type": "string" },
|
|
161
|
+
"title": { "type": "string" }
|
|
162
|
+
},
|
|
163
|
+
"required": ["owner", "repo", "title"],
|
|
164
|
+
"additionalProperties": false
|
|
165
|
+
}
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
## Base URLs — don't duplicate the version segment
|
|
169
|
+
|
|
170
|
+
Every integration has a base URL baked in. Your paths are appended to it. If the base is already `https://api.notion.com/v1`, write `/pages` — not `/v1/pages`.
|
|
171
|
+
|
|
172
|
+
## Vibe-coding workflow
|
|
173
|
+
|
|
174
|
+
1. **Understand** what the user wants the tool to do
|
|
175
|
+
2. **Explore first** — use existing read tools (or build a quick `list_*` tool) to understand the API shape, field names, and ID formats
|
|
176
|
+
3. **Draft** the write tool with the correct input schema and handler
|
|
177
|
+
4. **Test** with `commandable_test_custom_tool` — run it with representative input before persisting
|
|
178
|
+
5. **Persist** with `commandable_upsert_custom_tool` — the tool is live immediately
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
## Examples
|
|
183
|
+
|
|
184
|
+
The following are real tools taken from the Commandable integration library. Use these as reference for style, shape, and handler patterns.
|
|
185
|
+
|
|
186
|
+
---
|
|
187
|
+
|
|
188
|
+
### Worked example — Create a Stripe integration + add `list_customers`
|
|
189
|
+
|
|
190
|
+
**Step 1: Create the integration**
|
|
191
|
+
|
|
192
|
+
Call `commandable_upsert_custom_integration`:
|
|
193
|
+
|
|
194
|
+
```json
|
|
195
|
+
{
|
|
196
|
+
"label": "Stripe",
|
|
197
|
+
"base_url": "https://api.stripe.com/v1",
|
|
198
|
+
"auth_type": "custom",
|
|
199
|
+
"credential_fields": [
|
|
200
|
+
{ "name": "apiKey", "label": "API Key", "description": "Stripe secret key (starts with sk_)", "sensitive": true }
|
|
201
|
+
],
|
|
202
|
+
"credential_injection": {
|
|
203
|
+
"headers": {
|
|
204
|
+
"Authorization": "Bearer {{apiKey}}"
|
|
205
|
+
}
|
|
206
|
+
},
|
|
207
|
+
"health_check_path": "/customers?limit=1",
|
|
208
|
+
"connection_hint": "1. Open https://dashboard.stripe.com/apikeys\\n2. In **Standard keys**, copy your **Secret key** (`sk_...`)\\n3. Paste it here as `apiKey`"
|
|
209
|
+
}
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
This returns an `integration_id` and `credential_url`.
|
|
213
|
+
|
|
214
|
+
**Step 2: User enters credentials**
|
|
215
|
+
|
|
216
|
+
The user opens `credential_url` and enters `apiKey`. The model never sees it.
|
|
217
|
+
|
|
218
|
+
**Step 3: Add a tool against the new integration**
|
|
219
|
+
|
|
220
|
+
Call `commandable_upsert_custom_tool`:
|
|
221
|
+
|
|
222
|
+
```json
|
|
223
|
+
{
|
|
224
|
+
"integration_id": "<integration_id_from_create_integration>",
|
|
225
|
+
"name": "list_customers",
|
|
226
|
+
"label": "List Customers",
|
|
227
|
+
"description": "List Stripe customers (optionally limit the count).",
|
|
228
|
+
"scope": "read",
|
|
229
|
+
"input_schema": {
|
|
230
|
+
"type": "object",
|
|
231
|
+
"properties": {
|
|
232
|
+
"limit": { "type": "number", "minimum": 1, "maximum": 100 }
|
|
233
|
+
},
|
|
234
|
+
"required": [],
|
|
235
|
+
"additionalProperties": false
|
|
236
|
+
},
|
|
237
|
+
"handler_code": "async (input) => {\\n const params = new URLSearchParams();\\n if (input.limit) params.set('limit', String(input.limit));\\n const q = params.toString() ? `?${params.toString()}` : '';\\n const res = await integration.fetch(`/customers${q}`);\\n return await res.json();\\n}"
|
|
238
|
+
}
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
---
|
|
242
|
+
|
|
243
|
+
### Worked example — Create a Basic Auth integration
|
|
244
|
+
|
|
245
|
+
If an API uses Basic Auth, do:
|
|
246
|
+
|
|
247
|
+
```json
|
|
248
|
+
{
|
|
249
|
+
"label": "My Internal API",
|
|
250
|
+
"base_url": "https://internal.example.com/api",
|
|
251
|
+
"auth_type": "basic",
|
|
252
|
+
"credential_fields": [
|
|
253
|
+
{ "name": "username", "label": "Username" },
|
|
254
|
+
{ "name": "password", "label": "Password", "sensitive": true }
|
|
255
|
+
],
|
|
256
|
+
"basic_username_field": "username",
|
|
257
|
+
"basic_password_field": "password",
|
|
258
|
+
"health_check_path": "/health",
|
|
259
|
+
"connection_hint": "Please enter the user name and password provided on the my account page https://internal.example.com/my-account"
|
|
260
|
+
}
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
---
|
|
264
|
+
|
|
265
|
+
### Example 1 — Trello: list the cards on a board list (read)
|
|
266
|
+
|
|
267
|
+
**What it does**: fetches all cards in a given Trello list (you need the list ID, which you can get from `get_board_lists`).
|
|
268
|
+
|
|
269
|
+
```js
|
|
270
|
+
// handler_code
|
|
271
|
+
async (input) => {
|
|
272
|
+
const res = await integration.fetch(`/lists/${input.listId}/cards`)
|
|
273
|
+
return await res.json()
|
|
274
|
+
}
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
```json
|
|
278
|
+
// input_schema
|
|
279
|
+
{
|
|
280
|
+
"type": "object",
|
|
281
|
+
"properties": {
|
|
282
|
+
"listId": { "type": "string" }
|
|
283
|
+
},
|
|
284
|
+
"required": ["listId"],
|
|
285
|
+
"additionalProperties": false
|
|
286
|
+
}
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
---
|
|
290
|
+
|
|
291
|
+
### Example 2 — Trello: create a card (write)
|
|
292
|
+
|
|
293
|
+
**What it does**: creates a new card in a list. Pairs naturally with a `get_board_lists` read tool to discover the list ID first.
|
|
294
|
+
|
|
295
|
+
```js
|
|
296
|
+
// handler_code
|
|
297
|
+
async (input) => {
|
|
298
|
+
const params = new URLSearchParams()
|
|
299
|
+
params.set('idList', input.idList)
|
|
300
|
+
params.set('name', input.name)
|
|
301
|
+
if (input.desc) params.set('desc', input.desc)
|
|
302
|
+
if (input.due) params.set('due', input.due)
|
|
303
|
+
const res = await integration.fetch(`/cards?${params.toString()}`, { method: 'POST' })
|
|
304
|
+
const card = await res.json()
|
|
305
|
+
console.log('Created card:', card.name, card.url)
|
|
306
|
+
return { id: card.id, name: card.name, url: card.url }
|
|
307
|
+
}
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
```json
|
|
311
|
+
// input_schema
|
|
312
|
+
{
|
|
313
|
+
"type": "object",
|
|
314
|
+
"properties": {
|
|
315
|
+
"idList": { "type": "string" },
|
|
316
|
+
"name": { "type": "string" },
|
|
317
|
+
"desc": { "type": "string" },
|
|
318
|
+
"due": { "type": "string", "description": "ISO 8601 due date, e.g. 2025-12-01T12:00:00Z" }
|
|
319
|
+
},
|
|
320
|
+
"required": ["idList", "name"],
|
|
321
|
+
"additionalProperties": false
|
|
322
|
+
}
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
---
|
|
326
|
+
|
|
327
|
+
### Example 3 — GitHub: list open issues on a repo (read)
|
|
328
|
+
|
|
329
|
+
**What it does**: lists issues for a given owner/repo, filterable by state and labels.
|
|
330
|
+
|
|
331
|
+
```js
|
|
332
|
+
// handler_code
|
|
333
|
+
async (input) => {
|
|
334
|
+
const params = new URLSearchParams()
|
|
335
|
+
if (input.state) params.set('state', input.state)
|
|
336
|
+
if (input.labels) params.set('labels', input.labels)
|
|
337
|
+
if (input.per_page) params.set('per_page', String(input.per_page))
|
|
338
|
+
const query = params.toString() ? `?${params.toString()}` : ''
|
|
339
|
+
const res = await integration.fetch(`/repos/${input.owner}/${input.repo}/issues${query}`)
|
|
340
|
+
return await res.json()
|
|
341
|
+
}
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
```json
|
|
345
|
+
// input_schema
|
|
346
|
+
{
|
|
347
|
+
"type": "object",
|
|
348
|
+
"properties": {
|
|
349
|
+
"owner": { "type": "string" },
|
|
350
|
+
"repo": { "type": "string" },
|
|
351
|
+
"state": { "type": "string", "enum": ["open", "closed", "all"] },
|
|
352
|
+
"labels": { "type": "string", "description": "Comma-separated label names" },
|
|
353
|
+
"per_page": { "type": "number" }
|
|
354
|
+
},
|
|
355
|
+
"required": ["owner", "repo"],
|
|
356
|
+
"additionalProperties": false
|
|
357
|
+
}
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
---
|
|
361
|
+
|
|
362
|
+
### Example 4 — GitHub: create an issue (write)
|
|
363
|
+
|
|
364
|
+
**What it does**: opens a new GitHub issue on a repo.
|
|
365
|
+
|
|
366
|
+
```js
|
|
367
|
+
// handler_code
|
|
368
|
+
async (input) => {
|
|
369
|
+
const res = await integration.fetch(`/repos/${input.owner}/${input.repo}/issues`, {
|
|
370
|
+
method: 'POST',
|
|
371
|
+
body: {
|
|
372
|
+
title: input.title,
|
|
373
|
+
body: input.body,
|
|
374
|
+
assignees: input.assignees,
|
|
375
|
+
labels: input.labels,
|
|
376
|
+
},
|
|
377
|
+
})
|
|
378
|
+
const issue = await res.json()
|
|
379
|
+
console.log('Created issue #' + issue.number + ':', issue.title)
|
|
380
|
+
return { number: issue.number, url: issue.html_url, title: issue.title }
|
|
381
|
+
}
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
```json
|
|
385
|
+
// input_schema
|
|
386
|
+
{
|
|
387
|
+
"type": "object",
|
|
388
|
+
"properties": {
|
|
389
|
+
"owner": { "type": "string" },
|
|
390
|
+
"repo": { "type": "string" },
|
|
391
|
+
"title": { "type": "string" },
|
|
392
|
+
"body": { "type": "string" },
|
|
393
|
+
"assignees": { "type": "array", "items": { "type": "string" } },
|
|
394
|
+
"labels": { "type": "array", "items": { "type": "string" } }
|
|
395
|
+
},
|
|
396
|
+
"required": ["owner", "repo", "title"],
|
|
397
|
+
"additionalProperties": false
|
|
398
|
+
}
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
---
|
|
402
|
+
|
|
403
|
+
### Example 5 — Notion: query a database (read)
|
|
404
|
+
|
|
405
|
+
**What it does**: runs a filtered/sorted query against a Notion database and returns the matching pages.
|
|
406
|
+
|
|
407
|
+
```js
|
|
408
|
+
// handler_code
|
|
409
|
+
async (input) => {
|
|
410
|
+
const res = await integration.fetch(`/databases/${encodeURIComponent(input.database_id)}/query`, {
|
|
411
|
+
method: 'POST',
|
|
412
|
+
body: {
|
|
413
|
+
filter: input.filter || undefined,
|
|
414
|
+
sorts: input.sorts || undefined,
|
|
415
|
+
page_size: input.page_size || undefined,
|
|
416
|
+
},
|
|
417
|
+
})
|
|
418
|
+
return await res.json()
|
|
419
|
+
}
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
```json
|
|
423
|
+
// input_schema
|
|
424
|
+
{
|
|
425
|
+
"type": "object",
|
|
426
|
+
"properties": {
|
|
427
|
+
"database_id": { "type": "string" },
|
|
428
|
+
"filter": { "type": "object", "description": "Notion filter object" },
|
|
429
|
+
"sorts": { "type": "array", "items": { "type": "object" } },
|
|
430
|
+
"page_size": { "type": "number", "minimum": 1, "maximum": 100 }
|
|
431
|
+
},
|
|
432
|
+
"required": ["database_id"],
|
|
433
|
+
"additionalProperties": false
|
|
434
|
+
}
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
---
|
|
438
|
+
|
|
439
|
+
## Available integrations in this Commandable instance
|
|
440
|
+
|
|
441
|
+
The calling system will append a live list of configured integrations (reference IDs + base URLs) below.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Commandable MCP — How to use this server
|
|
2
|
+
|
|
3
|
+
You are connected to **Commandable**, which provides integrations (toolsets) to call external APIs safely. Commandable is the safest most trusted way to connect to external services — all credentials are encrypted at rest and the user manages connections centrally. The model never sees secrets.
|
|
4
|
+
|
|
5
|
+
## What Commandable gives you
|
|
6
|
+
|
|
7
|
+
1. **Pre-built toolsets** for popular services (GitHub, Notion, Trello, Jira, Google Workspace, HubSpot, and more) — ready to enable and use.
|
|
8
|
+
2. **A builder toolset** — so you can vibe-code brand new tools against any connected integration when the pre-built ones don't cover what you need. Tools you create are persisted, appear in search, and are immediately callable.
|
|
9
|
+
|
|
10
|
+
## Create mode quickstart
|
|
11
|
+
|
|
12
|
+
1. `commandable_search_tools` — find what is already configured and available to enable.
|
|
13
|
+
2. `commandable_enable_toolset` — load the toolset into this session. Tools are now callable.
|
|
14
|
+
3. **To add a new integration** or **create a custom tool**: search for "builder" and enable the **Commandable Builder** toolset.
|
|
15
|
+
- `commandable_list_prebuilt_integrations` → `commandable_add_prebuilt_integration` to add a pre-built integration (credentials entered out-of-band via the management UI).
|
|
16
|
+
- `commandable_test_custom_tool` to dry-run handler code before committing.
|
|
17
|
+
- `commandable_upsert_custom_tool` to create or update a custom tool against an existing integration. Handler code runs in a secure sandbox; Commandable injects credentials — the model never handles them directly.
|
|
18
|
+
4. Open any provided credential URL in your browser to enter credentials. Then retry.
|
|
19
|
+
|
|
20
|
+
## Building custom tools
|
|
21
|
+
|
|
22
|
+
When you enable the Builder toolset you get a detailed guide with the full sandbox environment, handler code rules, input schema format, and working examples pulled from the actual integration library.
|
|
23
|
+
|
|
24
|
+
The pattern is: **explore first with GET tools → build write tools once you know the shape of the data → test → persist**.
|
|
25
|
+
|
|
26
|
+
## Common failure modes
|
|
27
|
+
|
|
28
|
+
- **Missing credentials** — a tool call fails with a credentials error. Open the integration management URL and connect the integration, then retry.
|
|
29
|
+
- **Wrong path** — paths in handler code are relative to the integration's base URL. Don't duplicate version segments that are already part of the base (e.g. don't write `/v1/...` if the base is already `https://api.example.com/v1`).
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
2
|
+
import type { ExecutableTool } from '../types.js';
|
|
3
|
+
import type { AbilityCatalog } from './abilityCatalog.js';
|
|
4
|
+
import type { SessionAbilityState } from './sessionState.js';
|
|
5
|
+
import type { MetaToolContext } from './metaTools.js';
|
|
6
|
+
export interface ToolIndex {
|
|
7
|
+
list: Array<{
|
|
8
|
+
name: string;
|
|
9
|
+
description?: string;
|
|
10
|
+
inputSchema: any;
|
|
11
|
+
}>;
|
|
12
|
+
byName: Map<string, ExecutableTool>;
|
|
13
|
+
}
|
|
14
|
+
export declare function registerToolHandlers(server: Server, tools: ToolIndex, createMode?: {
|
|
15
|
+
catalogRef: {
|
|
16
|
+
current: AbilityCatalog;
|
|
17
|
+
};
|
|
18
|
+
sessionState: SessionAbilityState;
|
|
19
|
+
ctx?: MetaToolContext;
|
|
20
|
+
}): void;
|
|
21
|
+
//# sourceMappingURL=handlers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handlers.d.ts","sourceRoot":"","sources":["../../src/mcp/handlers.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAA;AACvE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AACjD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA;AACzD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAA;AAE5D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAA;AAErD,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,GAAG,CAAA;KAAE,CAAC,CAAA;IACrE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,CAAA;CACpC;AAaD,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,SAAS,EAChB,UAAU,CAAC,EAAE;IAAE,UAAU,EAAE;QAAE,OAAO,EAAE,cAAc,CAAA;KAAE,CAAC;IAAC,YAAY,EAAE,mBAAmB,CAAC;IAAC,GAAG,CAAC,EAAE,eAAe,CAAA;CAAE,GACjH,IAAI,CAwFN"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js';
|
|
2
|
+
import { getMetaToolDefinitions, handleMetaToolCall } from './metaTools.js';
|
|
3
|
+
function formatAsText(value) {
|
|
4
|
+
if (typeof value === 'string')
|
|
5
|
+
return value;
|
|
6
|
+
try {
|
|
7
|
+
return JSON.stringify(value, null, 2);
|
|
8
|
+
}
|
|
9
|
+
catch {
|
|
10
|
+
return String(value);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
export function registerToolHandlers(server, tools, createMode) {
|
|
14
|
+
const metaToolDefs = getMetaToolDefinitions();
|
|
15
|
+
server.setRequestHandler(ListToolsRequestSchema, async (_req, extra) => {
|
|
16
|
+
if (!createMode)
|
|
17
|
+
return { tools: tools.list };
|
|
18
|
+
const sessionId = extra?.sessionId;
|
|
19
|
+
const active = createMode.sessionState.getActiveToolNames(sessionId);
|
|
20
|
+
const toolDefs = createMode.catalogRef.current.getToolDefinitions([...active]);
|
|
21
|
+
return { tools: [...metaToolDefs, ...toolDefs] };
|
|
22
|
+
});
|
|
23
|
+
server.setRequestHandler(CallToolRequestSchema, async (req, extra) => {
|
|
24
|
+
const name = req.params.name;
|
|
25
|
+
const args = (req.params.arguments ?? {});
|
|
26
|
+
const sessionId = extra?.sessionId;
|
|
27
|
+
if (createMode) {
|
|
28
|
+
const metaRes = await handleMetaToolCall({
|
|
29
|
+
name,
|
|
30
|
+
args,
|
|
31
|
+
sessionId,
|
|
32
|
+
catalog: createMode.catalogRef.current,
|
|
33
|
+
sessionState: createMode.sessionState,
|
|
34
|
+
ctx: createMode.ctx,
|
|
35
|
+
});
|
|
36
|
+
if (metaRes.handled) {
|
|
37
|
+
if (metaRes.listChanged) {
|
|
38
|
+
await server.sendToolListChanged();
|
|
39
|
+
}
|
|
40
|
+
return {
|
|
41
|
+
content: [{ type: 'text', text: formatAsText(metaRes.result) }],
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
if (!createMode.sessionState.isToolActive(sessionId, name)) {
|
|
45
|
+
throw new Error(`Tool not enabled in this session: ${name}. Use ${metaToolDefs[0].name} + ${metaToolDefs[1].name} to enable a toolset first.`);
|
|
46
|
+
}
|
|
47
|
+
const tool = createMode.catalogRef.current.getExecutableTool(name);
|
|
48
|
+
if (!tool)
|
|
49
|
+
throw new Error(`Unknown tool: ${name}`);
|
|
50
|
+
const res = await tool.run(args);
|
|
51
|
+
if (!res.success) {
|
|
52
|
+
return {
|
|
53
|
+
content: [
|
|
54
|
+
{ type: 'text', text: `Tool error: ${formatAsText(res.result)}` },
|
|
55
|
+
...(res.logs?.length ? [{ type: 'text', text: `Logs:\n${res.logs.join('\n')}` }] : []),
|
|
56
|
+
],
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
return {
|
|
60
|
+
content: [
|
|
61
|
+
{ type: 'text', text: formatAsText(res.result) },
|
|
62
|
+
...(res.logs?.length ? [{ type: 'text', text: `Logs:\n${res.logs.join('\n')}` }] : []),
|
|
63
|
+
],
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
const tool = tools.byName.get(name);
|
|
67
|
+
if (!tool)
|
|
68
|
+
throw new Error(`Unknown tool: ${name}`);
|
|
69
|
+
const res = await tool.run(args);
|
|
70
|
+
if (!res.success) {
|
|
71
|
+
return {
|
|
72
|
+
content: [
|
|
73
|
+
{ type: 'text', text: `Tool error: ${formatAsText(res.result)}` },
|
|
74
|
+
...(res.logs?.length ? [{ type: 'text', text: `Logs:\n${res.logs.join('\n')}` }] : []),
|
|
75
|
+
],
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
return {
|
|
79
|
+
content: [
|
|
80
|
+
{ type: 'text', text: formatAsText(res.result) },
|
|
81
|
+
...(res.logs?.length ? [{ type: 'text', text: `Logs:\n${res.logs.join('\n')}` }] : []),
|
|
82
|
+
],
|
|
83
|
+
};
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=handlers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handlers.js","sourceRoot":"","sources":["../../src/mcp/handlers.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import type { AbilityCatalog } from './abilityCatalog.js';
|
|
2
|
+
import type { SessionAbilityState } from './sessionState.js';
|
|
3
|
+
import type { McpToolDefinition } from './toolAdapter.js';
|
|
4
|
+
import type { DbClient } from '../db/client.js';
|
|
5
|
+
import type { SqlCredentialStore } from '../db/credentialStore.js';
|
|
6
|
+
import type { IntegrationData } from '../types.js';
|
|
7
|
+
import type { IntegrationProxy } from '../integrations/proxy.js';
|
|
8
|
+
import type { IntegrationTypeConfig } from '../types.js';
|
|
9
|
+
export declare const META_TOOL_NAMES: {
|
|
10
|
+
readonly readme: "commandable_readme";
|
|
11
|
+
readonly searchTools: "commandable_search_tools";
|
|
12
|
+
readonly enableToolset: "commandable_enable_toolset";
|
|
13
|
+
readonly disableToolset: "commandable_disable_toolset";
|
|
14
|
+
readonly listPrebuiltIntegrations: "commandable_list_prebuilt_integrations";
|
|
15
|
+
readonly addPrebuiltIntegration: "commandable_add_prebuilt_integration";
|
|
16
|
+
readonly upsertCustomIntegration: "commandable_upsert_custom_integration";
|
|
17
|
+
readonly upsertCustomTool: "commandable_upsert_custom_tool";
|
|
18
|
+
readonly deleteCustomIntegration: "commandable_delete_custom_integration";
|
|
19
|
+
readonly deleteCustomTool: "commandable_delete_custom_tool";
|
|
20
|
+
readonly testCustomTool: "commandable_test_custom_tool";
|
|
21
|
+
};
|
|
22
|
+
export type MetaToolName = typeof META_TOOL_NAMES[keyof typeof META_TOOL_NAMES];
|
|
23
|
+
export type { McpToolDefinition } from './toolAdapter.js';
|
|
24
|
+
export type MetaToolContext = {
|
|
25
|
+
spaceId: string;
|
|
26
|
+
db: DbClient;
|
|
27
|
+
credentialStore: SqlCredentialStore;
|
|
28
|
+
proxy: IntegrationProxy;
|
|
29
|
+
/**
|
|
30
|
+
* Optional. If set, meta-tools can return URLs like:
|
|
31
|
+
* `${credentialSetupBaseUrl}/integrations/<integrationId>`
|
|
32
|
+
*/
|
|
33
|
+
credentialSetupBaseUrl?: string;
|
|
34
|
+
/**
|
|
35
|
+
* Mutable reference used by create mode. If supplied, meta-tools may update
|
|
36
|
+
* it after adding integrations (e.g., push new record or reload from DB).
|
|
37
|
+
*/
|
|
38
|
+
integrationsRef?: {
|
|
39
|
+
current: IntegrationData[];
|
|
40
|
+
};
|
|
41
|
+
integrationTypeConfigsRef?: {
|
|
42
|
+
current: IntegrationTypeConfig[];
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* Mutable reference to tool index + catalog. If supplied, meta-tools may
|
|
46
|
+
* dynamically register new tools and rebuild the catalog.
|
|
47
|
+
*
|
|
48
|
+
* (Wired in during the \"dynamic tool loading\" step.)
|
|
49
|
+
*/
|
|
50
|
+
toolIndexRef?: {
|
|
51
|
+
byName: Map<string, any>;
|
|
52
|
+
list?: Array<{
|
|
53
|
+
name: string;
|
|
54
|
+
description?: string;
|
|
55
|
+
inputSchema: any;
|
|
56
|
+
}>;
|
|
57
|
+
};
|
|
58
|
+
catalogRef?: {
|
|
59
|
+
current: AbilityCatalog;
|
|
60
|
+
};
|
|
61
|
+
};
|
|
62
|
+
export declare function getMetaToolDefinitions(): McpToolDefinition[];
|
|
63
|
+
export declare function getBuilderToolDefinitions(): McpToolDefinition[];
|
|
64
|
+
export type MetaToolCallResult = {
|
|
65
|
+
handled: false;
|
|
66
|
+
} | {
|
|
67
|
+
handled: true;
|
|
68
|
+
listChanged: boolean;
|
|
69
|
+
result: any;
|
|
70
|
+
};
|
|
71
|
+
export declare function handleMetaToolCall(params: {
|
|
72
|
+
name: string;
|
|
73
|
+
args: any;
|
|
74
|
+
sessionId: string | undefined;
|
|
75
|
+
catalog: AbilityCatalog;
|
|
76
|
+
sessionState: SessionAbilityState;
|
|
77
|
+
ctx?: MetaToolContext;
|
|
78
|
+
}): Promise<MetaToolCallResult>;
|
|
79
|
+
//# sourceMappingURL=metaTools.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metaTools.d.ts","sourceRoot":"","sources":["../../src/mcp/metaTools.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA;AAEzD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAA;AAC5D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAA;AASzD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAA;AAE/C,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAA;AAClE,OAAO,KAAK,EAAgC,eAAe,EAAE,MAAM,aAAa,CAAA;AAChF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAA;AAYhE,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAA;AAExD,eAAO,MAAM,eAAe;;;;;;;;;;;;CAYlB,CAAA;AAEV,MAAM,MAAM,YAAY,GAAG,OAAO,eAAe,CAAC,MAAM,OAAO,eAAe,CAAC,CAAA;AAE/E,YAAY,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAA;AAoCzD,MAAM,MAAM,eAAe,GAAG;IAC5B,OAAO,EAAE,MAAM,CAAA;IACf,EAAE,EAAE,QAAQ,CAAA;IACZ,eAAe,EAAE,kBAAkB,CAAA;IACnC,KAAK,EAAE,gBAAgB,CAAA;IACvB;;;OAGG;IACH,sBAAsB,CAAC,EAAE,MAAM,CAAA;IAC/B;;;OAGG;IACH,eAAe,CAAC,EAAE;QAAE,OAAO,EAAE,eAAe,EAAE,CAAA;KAAE,CAAA;IAChD,yBAAyB,CAAC,EAAE;QAAE,OAAO,EAAE,qBAAqB,EAAE,CAAA;KAAE,CAAA;IAChE;;;;;OAKG;IACH,YAAY,CAAC,EAAE;QACb,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;QACxB,IAAI,CAAC,EAAE,KAAK,CAAC;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,WAAW,CAAC,EAAE,MAAM,CAAC;YAAC,WAAW,EAAE,GAAG,CAAA;SAAE,CAAC,CAAA;KACvE,CAAA;IACD,UAAU,CAAC,EAAE;QAAE,OAAO,EAAE,cAAc,CAAA;KAAE,CAAA;CACzC,CAAA;AAED,wBAAgB,sBAAsB,IAAI,iBAAiB,EAAE,CA6C5D;AAED,wBAAgB,yBAAyB,IAAI,iBAAiB,EAAE,CAyI/D;AAED,MAAM,MAAM,kBAAkB,GAC1B;IAAE,OAAO,EAAE,KAAK,CAAA;CAAE,GAClB;IAAE,OAAO,EAAE,IAAI,CAAC;IAAC,WAAW,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,GAAG,CAAA;CAAE,CAAA;AAExD,wBAAsB,kBAAkB,CAAC,MAAM,EAAE;IAC/C,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,GAAG,CAAA;IACT,SAAS,EAAE,MAAM,GAAG,SAAS,CAAA;IAC7B,OAAO,EAAE,cAAc,CAAA;IACvB,YAAY,EAAE,mBAAmB,CAAA;IACjC,GAAG,CAAC,EAAE,eAAe,CAAA;CACtB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAisB9B"}
|