callman-mcp 0.2.0 → 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.
Files changed (63) hide show
  1. package/CHANGELOG.md +56 -0
  2. package/README.md +4 -4
  3. package/dist/client/api.d.ts +16 -1
  4. package/dist/client/api.d.ts.map +1 -1
  5. package/dist/client/api.js +22 -0
  6. package/dist/client/api.js.map +1 -1
  7. package/dist/client/types.d.ts +14 -0
  8. package/dist/client/types.d.ts.map +1 -1
  9. package/dist/domain/diagram/build.d.ts +122 -73
  10. package/dist/domain/diagram/build.d.ts.map +1 -1
  11. package/dist/domain/diagram/build.js +51 -167
  12. package/dist/domain/diagram/build.js.map +1 -1
  13. package/dist/domain/diagram/layout.d.ts +5 -4
  14. package/dist/domain/diagram/layout.d.ts.map +1 -1
  15. package/dist/domain/diagram/layout.js +18 -45
  16. package/dist/domain/diagram/layout.js.map +1 -1
  17. package/dist/domain/diagram/patch.d.ts +1011 -92
  18. package/dist/domain/diagram/patch.d.ts.map +1 -1
  19. package/dist/domain/diagram/patch.js +113 -273
  20. package/dist/domain/diagram/patch.js.map +1 -1
  21. package/dist/domain/diagram/style.d.ts +4 -12
  22. package/dist/domain/diagram/style.d.ts.map +1 -1
  23. package/dist/domain/diagram/style.js +8 -84
  24. package/dist/domain/diagram/style.js.map +1 -1
  25. package/dist/domain/diagram/summarize.d.ts +26 -24
  26. package/dist/domain/diagram/summarize.d.ts.map +1 -1
  27. package/dist/domain/diagram/summarize.js +21 -35
  28. package/dist/domain/diagram/summarize.js.map +1 -1
  29. package/dist/domain/requestIntegrations.d.ts +20 -20
  30. package/dist/domain/requestShape.d.ts +32 -32
  31. package/dist/resources/docs/diagramSchema.d.ts +1 -1
  32. package/dist/resources/docs/diagramSchema.d.ts.map +1 -1
  33. package/dist/resources/docs/diagramSchema.js +87 -10
  34. package/dist/resources/docs/diagramSchema.js.map +1 -1
  35. package/dist/resources/docs/overview.d.ts +1 -1
  36. package/dist/resources/docs/overview.d.ts.map +1 -1
  37. package/dist/resources/docs/overview.js +4 -1
  38. package/dist/resources/docs/overview.js.map +1 -1
  39. package/dist/resources/generated/aiPacks.d.ts +1 -1
  40. package/dist/resources/generated/aiPacks.js +2 -2
  41. package/dist/tools/catalog.d.ts.map +1 -1
  42. package/dist/tools/catalog.js +5 -0
  43. package/dist/tools/catalog.js.map +1 -1
  44. package/dist/tools/diagrams.d.ts.map +1 -1
  45. package/dist/tools/diagrams.js +547 -59
  46. package/dist/tools/diagrams.js.map +1 -1
  47. package/dist/tools/lookups.d.ts +5 -1
  48. package/dist/tools/lookups.d.ts.map +1 -1
  49. package/dist/tools/lookups.js +41 -0
  50. package/dist/tools/lookups.js.map +1 -1
  51. package/dist-cjs/client/api.js +22 -0
  52. package/dist-cjs/domain/diagram/build.js +55 -171
  53. package/dist-cjs/domain/diagram/layout.js +19 -45
  54. package/dist-cjs/domain/diagram/patch.js +111 -271
  55. package/dist-cjs/domain/diagram/style.js +11 -88
  56. package/dist-cjs/domain/diagram/summarize.js +23 -35
  57. package/dist-cjs/resources/docs/diagramSchema.js +87 -10
  58. package/dist-cjs/resources/docs/overview.js +4 -1
  59. package/dist-cjs/resources/generated/aiPacks.js +2 -2
  60. package/dist-cjs/tools/catalog.js +5 -0
  61. package/dist-cjs/tools/diagrams.js +539 -51
  62. package/dist-cjs/tools/lookups.js +46 -1
  63. package/package.json +2 -2
@@ -92,39 +92,116 @@ asks for a specific arrangement. Keep diagrams readable: 8–25 nodes, short lab
92
92
  per relationship.
93
93
 
94
94
  ## Editing: patch_diagram ops
95
+ Ops describe CHANGES; the rest of the diagram stays exactly as it is. The op list below is the
96
+ same vocabulary the desktop's AI assistant uses — one implementation (callman-core) applies both.
95
97
  \`\`\`jsonc
96
98
  { "op": "addNode", "node": { "type": "db.redis", "label": "cache", "parent": "k8s" } }
97
99
  { "op": "updateNode", "id": "orders", "changes": { "label": "Orders API", "style": { "fill": "#EFF6FF" } } }
98
100
  { "op": "updateNode", "id": "orders", "changes": { "style": { "fill": null } } } // remove one style key
99
101
  { "op": "updateNode", "id": "orders", "changes": { "style": null } } // clear the style
100
102
  { "op": "removeNode", "id": "bus" } // its edges are removed, its children move to the top level
101
- { "op": "addEdge", "edge": { "source": "orders", "target": "n6", "semantic": "async", "color": "#F59E0B" } }
103
+ { "op": "addEdge", "edge": { "source": "orders", "target": "cache", "semantic": "async", "color": "#F59E0B" } }
102
104
  { "op": "updateEdge", "id": "e2", "changes": { "label": "gRPC", "semantic": "fallback" } } // color is kept
103
105
  { "op": "updateEdge", "id": "e2", "changes": { "color": null } } // back to the default color
104
106
  { "op": "removeEdge", "id": "e3" }
105
107
  { "op": "setTitle", "title": "New title" }
108
+ { "op": "moveNode", "id": "orders", "position": { "x": 320, "y": 80 } }
109
+ { "op": "reparent", "id": "orders", "parent": "k8s" } // null = top level
110
+ { "op": "setEdgeRoute", "id": "e2", "routing": "smart", "sourceSide": "right", "targetSide": "left" }
111
+ { "op": "reorder", "id": "k8s", "index": "back" }
112
+ { "op": "setCanvas", "canvas": { "background": "grid", "defaultRouting": "orthogonal" } }
113
+ { "op": "group", "ids": ["orders", "db"], "label": "Order domain" } // a new frame around them
114
+ { "op": "ungroup", "id": "k8s" } // members stay where they are
115
+ { "op": "relayout", "scope": "new" } // hint: place only the new nodes (or "all")
106
116
  \`\`\`
107
117
  - updateNode \`changes\` accepts: type, label, parent (null/"" = top level), position, size,
108
- style, rotation, locked, hidden, data. \`style\` and \`data\` MERGE into what the node has;
109
- a key set to null is removed.
118
+ style, rotation, locked, hidden, collapsed, data. \`style\` and \`data\` MERGE into what the
119
+ node has; a key set to null is removed.
110
120
  - updateEdge \`changes\` accepts: source, target, label ("" removes it), semantic, color,
111
- routing, markerEnd, markerStart.
121
+ routing, markerEnd, markerStart, sourceSide, targetSide (null = floating).
122
+ - Ids: a node written without an id gets a slug of its label (\`orders-service\`, \`-2\` on a
123
+ clash); the result's \`idMap\` reports any id that had to change.
112
124
  - Moving a node (position, size or parent) or re-pointing an edge drops the saved route of
113
125
  the edges involved; the studio re-routes them (\`reroutedEdges\` in the result).
114
126
  - \`relayout\`: \`new\` (default — only new nodes get a place), \`all\` (re-run layout), \`none\`.
115
127
  - \`get_diagram\` (view \`graph\`) returns nodes and edges in this same shape — ids, parents,
116
- styles, colors — so read it before a patch.
128
+ styles, colors, routing, sides — so read it before a patch.
129
+ - If someone saved the diagram between your read and your patch, the ops are re-applied on
130
+ the newer version automatically (they describe intent, not a whole document).
131
+
132
+ ## Mermaid
133
+ - \`get_diagram\` view \`mermaid\` renders any diagram as a Mermaid flowchart (\`id@{ shape, label }\`
134
+ nodes, \`subgraph\` containers, \`e1@-->\` edge ids, \`-->\`/\`-.->\`/\`==>\` for sync/async/bus).
135
+ - \`create_diagram\` / \`update_diagram\` accept \`source: { format: "mermaid", text }\` instead of
136
+ nodes: a flowchart/graph becomes nodes and edges (laid out automatically) and the text stays
137
+ attached as the diagram's source — later ops keep it in sync (the desktop shows both).
138
+ Bracket shapes map to component types (\`[( )]\` → database, \`{ }\` → decision, \`([ ])\` →
139
+ terminator …); \`click\`, \`%%\` comments and unknown statements are kept untouched.
140
+ - Any other Mermaid type (sequenceDiagram, classDiagram, erDiagram …) is stored as source only:
141
+ \`get_diagram\` view \`source\` returns it, the desktop previews it, and structural ops are
142
+ refused with \`DIAGRAM_SOURCE_UNSUPPORTED_TYPE\`.
143
+
144
+ ## BPMN
145
+ - A BPMN diagram keeps its truth in BPMN 2.0 XML: \`create_diagram\` with \`kind: "bpmn"\` (or nodes
146
+ typed bpmn.*) writes the XML from your nodes and edges; \`source: { format: "bpmn", text }\` stores a
147
+ file you already have (from Camunda Modeler, for example). The desktop opens it in its BPMN editor.
148
+ - Node \`type\` is one of the bpmn.* types listed under DIAGRAM OPS above (bpmn.start-event,
149
+ bpmn.user-task, bpmn.service-task, bpmn.exclusive-gateway, bpmn.parallel-gateway, bpmn.subprocess,
150
+ bpmn.pool, bpmn.lane, bpmn.boundary-event …). \`data.bpmn\` carries the BPMN facts:
151
+ \`eventDefinition\` (message | timer | error | signal | …), \`attachedTo\` (boundary events),
152
+ \`cancelActivity\`, \`isExpanded\`. Edges are sequence flows; \`data.bpmn\` may set
153
+ \`flow: "message"\` (between pools), \`conditionExpression\` and \`isDefault\`.
154
+ - Pools and lanes are containers (\`parent\`); a boundary event's parent is its host's parent.
155
+ New nodes need no position: they are placed after their predecessor.
156
+ - \`patch_diagram\` works as on any diagram: every op lands on the XML as a minimal edit — extension
157
+ elements, annotations and the modeler's formatting stay untouched. \`get_diagram\` view \`source\`
158
+ returns the XML; view \`graph\` shows the derived nodes/edges with their \`bpmn\` facts.
159
+
160
+ ## Database diagrams (ERD)
161
+ - A database diagram keeps its truth in a JSON database model (\`source.format: "database"\`):
162
+ tables (\`entities\`) with columns, keys, indexes and comments, and relationships between them;
163
+ the nodes on the canvas hold only positions and visibility. The desktop opens it on an ERD
164
+ canvas; \`get_diagram\` view \`schema\` shows tables with their columns and the relationships as
165
+ \`table.column\` pairs — read it before editing.
166
+ - Create one with \`create_diagram\`: \`tables\` + \`relationships\` (\`{ name, schema?, columns:
167
+ [{ name, dataType, primaryKey?, nullable?, unique?, defaultValue?, comment? }] }\` and
168
+ \`{ source: "orders.user_id", target: "users.id", cardinality: "N:1" }\` — source is the child /
169
+ foreign-key side), or nodes typed db.table / db.view / db.collection with the columns in
170
+ \`data.db.columns\`, or \`fromConnection\` to read a real database through one of the
171
+ workspace's connections (\`introspect_database\` reads the same schema without drawing it).
172
+ - Edit with the schema ops of \`patch_diagram\`:
173
+ \`\`\`jsonc
174
+ { "op": "addTable", "table": { "name": "payments", "columns": [{ "name": "id", "dataType": "uuid", "primaryKey": true }, { "name": "order_id", "dataType": "bigint" }, { "name": "amount", "dataType": "numeric(12,2)" }] } }
175
+ { "op": "addColumn", "table": "users", "column": { "name": "profile_id", "dataType": "uuid", "nullable": true }, "after": "id" }
176
+ { "op": "alterColumn", "table": "users", "column": "email", "changes": { "unique": true, "nullable": false } }
177
+ { "op": "removeColumn", "table": "users", "column": "nickname" }
178
+ { "op": "setPrimaryKey", "table": "order_items", "columns": ["order_id", "line"] }
179
+ { "op": "renameTable", "table": "users", "name": "accounts", "schema": "auth" }
180
+ { "op": "setTableComment", "table": "users", "comment": "People who can sign in" }
181
+ { "op": "addRelationship", "source": "payments.order_id", "target": "orders.id", "cardinality": "N:1" }
182
+ { "op": "updateRelationship", "relationship": "fk-payments-orders", "changes": { "cardinality": "1:1", "label": "settles" } }
183
+ { "op": "removeRelationship", "relationship": "fk-payments-orders" }
184
+ { "op": "removeTable", "table": "audit_log" } // its relationships go with it
185
+ { "op": "hideTable", "table": "migrations" } // canvas only; showTable brings it back
186
+ \`\`\`
187
+ Tables are named (\`users\`, \`public.users\`), columns as \`table.column\`; ids stay stable
188
+ across renames. New tables are placed to the right of the existing ones (or laid out with
189
+ \`relayout: "all"\`). moveNode, hideTable/showTable and setCanvas change the canvas only;
190
+ group / ungroup / reparent do not apply.
117
191
 
118
192
  ## Stored document (get_diagram view: "full")
119
193
  \`\`\`ts
120
194
  interface DiagramDocument {
121
195
  schemaVersion: 1; id: string;
122
- meta: { title: string; createdAt: string; updatedAt: string };
123
- canvas?: { background?: "grid" | "dots" | "blank"; gridSize?: number };
196
+ meta: { title: string; createdAt: string; updatedAt: string; revision?: number };
197
+ canvas?: { background?: "grid" | "dots" | "blank"; gridSize?: number;
198
+ defaultRouting?: "orthogonal" | "straight" | "curved" | "smart";
199
+ layout?: { algorithm; direction }; viewport?: { x; y; zoom } };
124
200
  nodes: { id; type; position: {x,y}; size: {width,height}; label?; parentId?; rotation?;
125
- locked?; hidden?; style?: DiagramStyle; data? }[];
126
- edges: { id; source?; target?; label?; routing?; style?: DiagramStyle; markerStart?; markerEnd?;
127
- waypoints?; sourceAnchor?; targetAnchor? }[];
201
+ locked?; hidden?; collapsed?; collapsedSize?; style?: DiagramStyle; data? }[];
202
+ edges: { id; source?; target?; label?; labelPosition?; routing?; sourceHandle?; targetHandle?;
203
+ style?: DiagramStyle; markerStart?; markerEnd?; waypoints? }[];
204
+ source?: { format: "mermaid" | "bpmn" | "database"; text; diagramType; grammar?; valid? };
128
205
  }
129
206
  // Stored colors are { raw: "#3B82F6" } (or a theme { token }); bold/italic/underline are
130
207
  // the bitmask fontStyle (1 | 2 | 4). The tools convert both ways — write plain colors.
@@ -62,7 +62,10 @@ partial node configs are merged over defaults. Runs happen on the server (\`run_
62
62
  ## Diagrams
63
63
  System-design diagrams use a fixed component catalog — \`callman://diagram/components\`.
64
64
  Build with \`create_diagram\` (auto layout), edit with \`patch_diagram\`, share with
65
- \`share_diagram\`. See \`callman://docs/diagram-schema\`.
65
+ \`share_diagram\`. See \`callman://docs/diagram-schema\`. The user's library has private
66
+ folders: \`list_diagrams\` shows the tree as paths ("Architecture/Payments"); file a
67
+ diagram with \`folder\` on \`create_diagram\` / \`update_diagram\`; manage folders with
68
+ \`create_diagram_folder\`, \`update_diagram_folder\`, \`delete_diagram_folder\`.
66
69
 
67
70
  ## After writing
68
71
  The desktop app refreshes when the user switches back to it. Tell the user what you created
@@ -1,8 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.AI_PACKS = exports.AI_PACKS_CORE_VERSION = void 0;
4
- // GENERATED by scripts/build-static-resources.mjs from callman-core@1.28.1 ai-packs — do not edit.
5
- exports.AI_PACKS_CORE_VERSION = "1.28.1";
4
+ // GENERATED by scripts/build-static-resources.mjs from callman-core@1.30.0 ai-packs — do not edit.
5
+ exports.AI_PACKS_CORE_VERSION = "1.30.0";
6
6
  exports.AI_PACKS = {
7
7
  "db-queries": "<!-- GENERATED FILE — do not edit by hand. Source: callman_core (npm run ai:packs). -->\n\n# Callman data access from scripts (`pm.db.query` / `pm.redis.command`)\n\n`pm.db.query({ connectionId, query })` — ALWAYS `await`. `query` is coerced to a string, `{{tokens}}` are resolved, then dispatched by the connection's type. `connectionId` may be omitted to use the request's configured DB connection. IMPORTANT: `pm.db.query` does NOT accept a `params`/bind array — inline values (quote strings) or use `{{env.X}}` tokens; SQL placeholders like `$1` or `?` are NOT bound.\n\n## MongoDB\n`query` MUST be a JSON STRING of a command object (use `JSON.stringify`), NOT a `db.coll.find(...)` shell string. The match key is `filter` (a top-level `query` key is rejected).\n\n```js\nconst body = pm.response.json();\nconst res = await pm.db.query({\n connectionId: \"…\",\n query: JSON.stringify({\n collection: \"users\",\n operation: \"findOne\", // find | findOne | aggregate | countDocuments | insertOne | insertMany | updateOne | updateMany | deleteOne | deleteMany | findOneAndUpdate | findOneAndReplace | findOneAndDelete\n filter: { email: body.data.user.email },\n }),\n});\npm.expect(res.rowCount).to.be.above(0); // existence check\n```\n\nPer-operation fields: `find`/`findOne` use `filter` (+ optional `projection`,`sort`,`limit`,`skip`); `aggregate` uses `pipeline` (array); `insertOne` uses `document`, `insertMany` uses `documents`; `updateOne`/`updateMany`/`findOneAndUpdate` use `filter`+`update` (Mongo update operators, e.g. `{ $set: { … } }`); `deleteOne`/`deleteMany` use `filter`; `findOneAndUpdate`/`findOneAndReplace` accept `returnDocument: \"before\"|\"after\"`. A 24-hex string in a filter is auto-coerced to ObjectId (or use `{ \"$oid\": \"…\" }`). Rows are in `res.rows`; write ops surface counts in `res.rowCount`.\n\n## PostgreSQL / MySQL / Oracle (SQL)\n`query` is plain SQL text. Because `pm.db.query` binds no params, inline the value and quote strings yourself (or use a `{{token}}`):\n\n```js\nconst email = pm.response.json().data.user.email;\nconst res = await pm.db.query({\n connectionId: \"…\",\n query: `SELECT id FROM users WHERE email = '${email}'`,\n});\npm.expect(res.rowCount).to.be.above(0);\n```\n\nNotes: a trailing `;` is stripped (except Oracle PL/SQL blocks, which keep it). **Oracle** returns column names UPPERCASE — read `res.rows[0].EMAIL`, not `.email`. `res.rowCount` is the row count for SELECT and the affected-row count for INSERT/UPDATE/DELETE.\n\n## SQL Server (mssql)\nSingle statement per query; a trailing `;` is stripped; `GO` batch separators are REJECTED (client-tool syntax, not T-SQL). Positional params bind as named inputs: `params[0]` → `@p1`, `params[1]` → `@p2`… (scenario db node only — `pm.db.query` has no params).\n\n```sql\nSELECT TOP 1 id, amount FROM dbo.orders WHERE customer_id = @p1 ORDER BY created_at DESC\n```\n\n## Redis (`pm.redis.command`)\n`command` is a single string. Supported commands: **GET, SET, DEL, EXISTS, TTL, HGET, HSET, HGETALL, HDEL, LPUSH, RPUSH, LRANGE, LLEN, SADD, SMEMBERS, SISMEMBER, INCR, DECR, INCRBY, EXPIRE, PERSIST, TYPE, ZADD, ZRANGE, ZSCORE, SCAN**. Quote a value that contains spaces.\n\nStructured replies land in `res.result` as real values: `HGETALL` → object, `LRANGE`/`SMEMBERS`/`ZRANGE` → array, `EXISTS`/`SISMEMBER`/`EXPIRE`/`PERSIST` → boolean; `res.resultText` is the stringified form. `SCAN pattern [count]` is Callman-managed: the cursor loop runs internally (capped at 1000 keys / 100 iterations) and returns `{ keys, count, truncated }` — no raw cursors.\n\n```js\nconst res = await pm.redis.command({ connectionId: \"…\", command: `GET session:${id}` });\npm.expect(res.success).to.be.true;\n// res.result / res.resultText hold the value; res.commandName, res.key are set.\n```\n",
8
8
  "diagram-components": "<!-- GENERATED FILE — do not edit by hand. Source: callman_core (npm run ai:packs). -->\n\n# Diagram components and edge notation\n\nA diagram node's `type` MUST be one of the keys below (`callman-core` `DIAGRAM_COMPONENT_CATALOG`). Sizes are the defaults the studio uses; `container` types hold children via `parentId`.\n\n## Edge notation\n\n| Semantic | Meaning | Style tuple |\n| --- | --- | --- |\n| `sync` | Request / response call | dashed=false, strokeWidth=1.5 |\n| `async` | Fire-and-forget, event or callback | dashed=true, dashPattern=\"6 4\", strokeWidth=1.5 |\n| `fallback` | Retry, fallback or optional path | dashed=true, dashPattern=\"1 3\", strokeWidth=1.25 |\n| `bus` | Message bus or stream | dashed=false, strokeWidth=3 |\n\n## Generic (`generic`)\n\n| Type | Label | Default size | Aliases |\n| --- | --- | --- | --- |\n| `line` | Line | 160×0 | connector, edge, link |\n| `arrow` | Arrow | 160×0 | connector, directed, link |\n| `line.dashed` | Dashed Line | 160×0 | dotted, connector |\n| `rect` | Rectangle | 140×64 | box, card |\n| `square` | Square | 90×90 | |\n| `ellipse` | Ellipse | 140×64 | oval |\n| `circle` | Circle | 90×90 | |\n| `diamond` | Diamond | 140×64 | rhombus |\n| `triangle` | Triangle | 140×64 | |\n| `hexagon` | Hexagon | 140×64 | |\n| `pentagon` | Pentagon | 140×64 | |\n| `octagon` | Octagon | 140×64 | |\n| `parallelogram` | Parallelogram | 140×64 | |\n| `trapezoid` | Trapezoid | 140×64 | |\n| `cylinder` | Cylinder | 140×64 | can, tube |\n| `cloud-shape` | Cloud | 140×64 | |\n| `callout` | Callout | 140×64 | speech, bubble |\n| `text` | Text | 120×36 | |\n| `sticky` | Sticky note | 140×100 | postit, comment |\n| `card` | Card | 140×64 | |\n| `frame` | Frame / Container (container) | 220×160 | group, container, boundary |\n| `pool.horizontal` | Pool (horizontal) (swimlane) | 360×220 | swimlane, lane, container, subsystem |\n| `pool.vertical` | Pool (vertical) (swimlane) | 220×360 | swimlane, lane, container, subsystem |\n| `image` | Image | 140×64 | picture |\n\n## Flowchart (`flowchart`)\n\n| Type | Label | Default size | Aliases |\n| --- | --- | --- | --- |\n| `flow.process` | Process | 140×64 | step, action |\n| `flow.alt-process` | Alternate Process | 140×64 | |\n| `flow.decision` | Decision | 140×100 | if, branch |\n| `flow.terminator` | Start / End | 130×56 | terminator, begin, stop |\n| `flow.data` | Data (I/O) | 140×64 | input, output, io |\n| `flow.document` | Document | 140×64 | |\n| `flow.multi-document` | Multi-Document | 140×64 | |\n| `flow.predefined` | Predefined Process | 140×64 | subroutine |\n| `flow.manual-input` | Manual Input | 140×64 | |\n| `flow.manual-op` | Manual Operation | 140×64 | |\n| `flow.preparation` | Preparation | 140×64 | |\n| `flow.stored-data` | Stored Data | 140×64 | |\n| `flow.database` | Database | 140×64 | db, store |\n| `flow.display` | Display | 140×64 | |\n| `flow.delay` | Delay | 140×64 | |\n| `flow.merge` | Merge | 140×64 | |\n| `flow.or` | Or | 140×64 | |\n| `flow.connector` | On-page Connector | 48×48 | |\n| `flow.off-page` | Off-page Connector | 140×64 | |\n| `flow.annotation` | Annotation | 140×64 | |\n\n## UML (`uml`)\n\n| Type | Label | Default size | Aliases |\n| --- | --- | --- | --- |\n| `uml.class` | Class | 140×64 | entity |\n| `uml.abstract` | Abstract Class | 140×64 | |\n| `uml.interface` | Interface | 140×64 | |\n| `uml.enum` | Enum | 140×64 | |\n| `uml.object` | Object | 140×64 | |\n| `uml.package` | Package | 140×64 | |\n| `uml.component` | Component | 140×64 | |\n| `uml.node` | Node / Deployment | 140×64 | |\n| `uml.actor` | Actor | 60×100 | user, role |\n| `uml.usecase` | Use Case | 140×64 | |\n| `uml.boundary` | Boundary | 140×64 | |\n| `uml.control` | Control | 140×64 | |\n| `uml.entity` | Entity | 140×64 | |\n| `uml.state` | State | 140×64 | |\n| `uml.initial` | Initial State | 36×36 | |\n| `uml.final` | Final State | 40×40 | |\n| `uml.decision` | Decision | 60×60 | |\n| `uml.note` | Note / Comment | 140×64 | comment |\n\n## ERD (`erd`)\n\n| Type | Label | Default size | Aliases |\n| --- | --- | --- | --- |\n| `erd.entity` | Entity | 140×64 | table |\n| `erd.weak-entity` | Weak Entity | 140×64 | |\n| `erd.attribute` | Attribute | 140×64 | |\n| `erd.key-attribute` | Key Attribute | 140×64 | pk, primary key |\n| `erd.multivalued` | Multivalued Attribute | 140×64 | |\n| `erd.derived` | Derived Attribute | 140×64 | |\n| `erd.relationship` | Relationship | 140×64 | |\n| `erd.identifying` | Identifying Relationship | 140×64 | |\n\n## Architecture (`networking`)\n\n| Type | Label | Default size | Aliases |\n| --- | --- | --- | --- |\n| `net.user` | User / Client | 60×100 | client, person |\n| `net.admin` | Admin | 60×100 | |\n| `net.browser` | Browser | 140×64 | |\n| `net.mobile` | Mobile Device | 90×130 | phone |\n| `net.desktop` | Desktop | 140×64 | |\n| `net.iot` | IoT Device | 140×64 | |\n| `net.server` | Server | 140×64 | |\n| `net.service` | Service | 140×64 | microservice |\n| `net.monolith` | Monolith | 140×64 | |\n| `net.api-gateway` | API Gateway | 140×64 | api, gateway |\n| `net.load-balancer` | Load Balancer | 140×64 | lb |\n| `net.reverse-proxy` | Reverse Proxy | 140×64 | proxy |\n| `net.firewall` | Firewall | 140×64 | waf |\n| `net.router` | Router | 140×64 | |\n| `net.switch` | Switch | 140×64 | |\n| `net.dns` | DNS | 140×64 | |\n| `net.cdn` | CDN | 140×64 | edge |\n| `net.cache` | Cache | 140×64 | |\n| `net.queue` | Queue | 140×64 | mq |\n| `net.websocket` | Web Socket | 140×64 | ws |\n| `net.rest` | REST endpoint | 140×64 | http, api |\n| `net.internet` | Internet / Cloud | 140×64 | wan |\n| `net.datacenter` | Datacenter | 140×64 | |\n| `net.container` | Container | 140×64 | |\n| `net.pod` | Pod | 140×64 | |\n| `net.vm` | Virtual Machine | 140×64 | vm |\n\n## Databases (`database`)\n\n| Type | Label | Default size | Aliases |\n| --- | --- | --- | --- |\n| `db.postgres` | PostgreSQL | 176×56 | postgres, pg |\n| `db.mysql` | MySQL | 176×56 | |\n| `db.mariadb` | MariaDB | 176×56 | |\n| `db.mongodb` | MongoDB | 176×56 | mongo |\n| `db.redis` | Redis | 176×56 | |\n| `db.sqlite` | SQLite | 176×56 | |\n| `db.mssql` | MS SQL Server | 176×56 | sqlserver, mssql |\n| `db.oracle` | Oracle | 176×56 | |\n| `db.cassandra` | Cassandra | 176×56 | |\n| `db.elasticsearch` | Elasticsearch | 176×56 | elastic, es |\n| `db.neo4j` | Neo4j | 176×56 | graph |\n| `db.couchdb` | CouchDB | 176×56 | couch |\n| `db.couchbase` | Couchbase | 176×56 | |\n| `db.clickhouse` | ClickHouse | 176×56 | |\n| `db.cockroachdb` | CockroachDB | 176×56 | cockroach |\n| `db.influxdb` | InfluxDB | 176×56 | influx, tsdb |\n| `db.snowflake` | Snowflake | 176×56 | |\n| `db.supabase` | Supabase | 176×56 | |\n\n## Messaging (`messaging`)\n\n| Type | Label | Default size | Aliases |\n| --- | --- | --- | --- |\n| `mq.kafka` | Apache Kafka | 176×56 | kafka |\n| `mq.rabbitmq` | RabbitMQ | 176×56 | rabbit, amqp |\n| `mq.nats` | NATS | 176×56 | |\n| `mq.pulsar` | Apache Pulsar | 176×56 | pulsar |\n| `mq.mqtt` | MQTT | 176×56 | |\n| `mq.pubsub` | Pub/Sub | 176×56 | pubsub |\n| `mq.activemq` | ActiveMQ | 176×56 | jms |\n\n## Languages (`language`)\n\n| Type | Label | Default size | Aliases |\n| --- | --- | --- | --- |\n| `lang.node` | Node.js | 176×56 | node, js runtime |\n| `lang.python` | Python | 176×56 | py |\n| `lang.java` | Java | 176×56 | jvm |\n| `lang.go` | Go | 176×56 | golang |\n| `lang.rust` | Rust | 176×56 | |\n| `lang.dotnet` | C# / .NET | 176×56 | csharp, c# |\n| `lang.typescript` | TypeScript | 176×56 | ts |\n| `lang.javascript` | JavaScript | 176×56 | js |\n| `lang.ruby` | Ruby | 176×56 | |\n| `lang.php` | PHP | 176×56 | |\n| `lang.kotlin` | Kotlin | 176×56 | |\n| `lang.swift` | Swift | 176×56 | |\n| `lang.scala` | Scala | 176×56 | |\n| `lang.elixir` | Elixir | 176×56 | |\n| `lang.cpp` | C++ | 176×56 | cpp |\n\n## Frameworks (`framework`)\n\n| Type | Label | Default size | Aliases |\n| --- | --- | --- | --- |\n| `fw.express` | Express | 176×56 | |\n| `fw.nestjs` | NestJS | 176×56 | nest |\n| `fw.spring` | Spring Boot | 176×56 | spring |\n| `fw.django` | Django | 176×56 | |\n| `fw.flask` | Flask | 176×56 | |\n| `fw.fastapi` | FastAPI | 176×56 | |\n| `fw.rails` | Rails | 176×56 | ruby on rails |\n| `fw.laravel` | Laravel | 176×56 | |\n| `fw.dotnet` | .NET | 176×56 | |\n| `fw.react` | React | 176×56 | |\n| `fw.vue` | Vue | 176×56 | vuejs |\n| `fw.angular` | Angular | 176×56 | |\n| `fw.next` | Next.js | 176×56 | nextjs |\n| `fw.nuxt` | Nuxt | 176×56 | nuxtjs |\n| `fw.svelte` | Svelte | 176×56 | sveltekit |\n| `fw.electron` | Electron | 176×56 | |\n| `fw.tailwind` | Tailwind | 176×56 | tailwindcss |\n| `fw.graphql` | GraphQL | 176×56 | |\n\n## DevOps / CI-CD (`devops`)\n\n| Type | Label | Default size | Aliases |\n| --- | --- | --- | --- |\n| `ops.docker` | Docker | 176×56 | |\n| `ops.k8s` | Kubernetes | 176×56 | k8s |\n| `ops.nginx` | Nginx | 176×56 | |\n| `ops.haproxy` | HAProxy | 176×56 | lb |\n| `ops.traefik` | Traefik | 176×56 | traefik |\n| `ops.terraform` | Terraform | 176×56 | iac |\n| `ops.ansible` | Ansible | 176×56 | |\n| `ops.jenkins` | Jenkins | 176×56 | ci |\n| `ops.gha` | GitHub Actions | 176×56 | ci, actions |\n| `ops.gitlab` | GitLab CI | 176×56 | ci |\n| `ops.argocd` | ArgoCD | 176×56 | gitops |\n| `ops.helm` | Helm | 176×56 | |\n| `ops.istio` | Istio | 176×56 | service mesh |\n| `ops.envoy` | Envoy | 176×56 | proxy |\n| `ops.consul` | Consul | 176×56 | |\n| `ops.vault` | Vault | 176×56 | secrets |\n| `ops.pm2` | PM2 | 176×56 | |\n| `ops.maven` | Maven | 176×56 | build |\n\n## Auth / Identity (`auth`)\n\n| Type | Label | Default size | Aliases |\n| --- | --- | --- | --- |\n| `auth.oidc` | OpenID Connect | 176×56 | oidc |\n| `auth.jwt` | JWT | 176×56 | token |\n| `auth.keycloak` | Keycloak | 176×56 | |\n| `auth.auth0` | Auth0 | 176×56 | |\n| `auth.okta` | Okta | 176×56 | |\n| `auth.firebase` | Firebase Auth | 176×56 | firebase |\n| `auth.oauth` | OAuth 2.0 | 176×56 | oauth |\n| `auth.saml` | SAML | 176×56 | |\n| `auth.ldap` | LDAP | 176×56 | |\n\n## Observability (`observability`)\n\n| Type | Label | Default size | Aliases |\n| --- | --- | --- | --- |\n| `obs.prometheus` | Prometheus | 176×56 | metrics |\n| `obs.grafana` | Grafana | 176×56 | dashboard |\n| `obs.datadog` | Datadog | 176×56 | |\n| `obs.sentry` | Sentry | 176×56 | errors |\n| `obs.elasticsearch` | Elasticsearch | 176×56 | elk |\n| `obs.logstash` | Logstash | 176×56 | elk |\n| `obs.kibana` | Kibana | 176×56 | elk |\n| `obs.jaeger` | Jaeger | 176×56 | tracing |\n| `obs.otel` | OpenTelemetry | 176×56 | otel, tracing |\n| `obs.newrelic` | New Relic | 176×56 | |\n\n## AWS (`aws`)\n\n| Type | Label | Default size | Aliases |\n| --- | --- | --- | --- |\n| `aws.ec2` | EC2 | 176×56 | aws |\n| `aws.lambda` | Lambda | 176×56 | aws |\n| `aws.s3` | S3 | 176×56 | aws |\n| `aws.ebs` | EBS | 176×56 | aws |\n| `aws.efs` | EFS | 176×56 | aws |\n| `aws.rds` | RDS | 176×56 | aws |\n| `aws.aurora` | Aurora | 176×56 | aws |\n| `aws.dynamodb` | DynamoDB | 176×56 | aws |\n| `aws.elasticache` | ElastiCache | 176×56 | aws |\n| `aws.redshift` | Redshift | 176×56 | aws |\n| `aws.vpc` | VPC | 176×56 | aws |\n| `aws.subnet` | Subnet | 176×56 | aws |\n| `aws.internet-gateway` | Internet Gateway | 176×56 | aws |\n| `aws.nat-gateway` | NAT Gateway | 176×56 | aws |\n| `aws.elb` | ELB | 176×56 | aws |\n| `aws.alb` | ALB | 176×56 | aws |\n| `aws.nlb` | NLB | 176×56 | aws |\n| `aws.api-gateway` | API Gateway | 176×56 | aws |\n| `aws.cloudfront` | CloudFront | 176×56 | aws |\n| `aws.route-53` | Route 53 | 176×56 | aws |\n| `aws.sqs` | SQS | 176×56 | aws |\n| `aws.sns` | SNS | 176×56 | aws |\n| `aws.eventbridge` | EventBridge | 176×56 | aws |\n| `aws.kinesis` | Kinesis | 176×56 | aws |\n| `aws.step-functions` | Step Functions | 176×56 | aws |\n| `aws.ecs` | ECS | 176×56 | aws |\n| `aws.eks` | EKS | 176×56 | aws |\n| `aws.fargate` | Fargate | 176×56 | aws |\n| `aws.ecr` | ECR | 176×56 | aws |\n| `aws.iam` | IAM | 176×56 | aws |\n| `aws.cognito` | Cognito | 176×56 | aws |\n| `aws.secrets-manager` | Secrets Manager | 176×56 | aws |\n| `aws.kms` | KMS | 176×56 | aws |\n| `aws.cloudwatch` | CloudWatch | 176×56 | aws |\n| `aws.cloudtrail` | CloudTrail | 176×56 | aws |\n| `aws.glue` | Glue | 176×56 | aws |\n| `aws.athena` | Athena | 176×56 | aws |\n| `aws.sagemaker` | SageMaker | 176×56 | aws |\n| `aws.appsync` | AppSync | 176×56 | aws |\n| `aws.amplify` | Amplify | 176×56 | aws |\n\n## Azure (`azure`)\n\n| Type | Label | Default size | Aliases |\n| --- | --- | --- | --- |\n| `azure.virtual-machine` | Virtual Machine | 176×56 | azure |\n| `azure.vm-scale-set` | VM Scale Set | 176×56 | azure |\n| `azure.app-service` | App Service | 176×56 | azure |\n| `azure.functions` | Functions | 176×56 | azure |\n| `azure.container-instances` | Container Instances | 176×56 | azure |\n| `azure.aks` | AKS | 176×56 | azure |\n| `azure.container-registry` | Container Registry | 176×56 | azure |\n| `azure.blob-storage` | Blob Storage | 176×56 | azure |\n| `azure.files` | Files | 176×56 | azure |\n| `azure.disk` | Disk | 176×56 | azure |\n| `azure.sql-database` | SQL Database | 176×56 | azure |\n| `azure.cosmos-db` | Cosmos DB | 176×56 | azure |\n| `azure.cache-for-redis` | Cache for Redis | 176×56 | azure |\n| `azure.synapse` | Synapse | 176×56 | azure |\n| `azure.virtual-network` | Virtual Network | 176×56 | azure |\n| `azure.load-balancer` | Load Balancer | 176×56 | azure |\n| `azure.application-gateway` | Application Gateway | 176×56 | azure |\n| `azure.front-door` | Front Door | 176×56 | azure |\n| `azure.service-bus` | Service Bus | 176×56 | azure |\n| `azure.event-hub` | Event Hub | 176×56 | azure |\n| `azure.event-grid` | Event Grid | 176×56 | azure |\n| `azure.key-vault` | Key Vault | 176×56 | azure |\n| `azure.entra-id` | Entra ID | 176×56 | azure |\n| `azure.monitor` | Monitor | 176×56 | azure |\n| `azure.application-insights` | Application Insights | 176×56 | azure |\n| `azure.logic-apps` | Logic Apps | 176×56 | azure |\n| `azure.api-management` | API Management | 176×56 | azure |\n\n## GCP (`gcp`)\n\n| Type | Label | Default size | Aliases |\n| --- | --- | --- | --- |\n| `gcp.compute-engine` | Compute Engine | 176×56 | gcp, google |\n| `gcp.app-engine` | App Engine | 176×56 | gcp, google |\n| `gcp.cloud-functions` | Cloud Functions | 176×56 | gcp, google |\n| `gcp.cloud-run` | Cloud Run | 176×56 | gcp, google |\n| `gcp.gke` | GKE | 176×56 | gcp, google |\n| `gcp.artifact-registry` | Artifact Registry | 176×56 | gcp, google |\n| `gcp.cloud-storage` | Cloud Storage | 176×56 | gcp, google |\n| `gcp.persistent-disk` | Persistent Disk | 176×56 | gcp, google |\n| `gcp.cloud-sql` | Cloud SQL | 176×56 | gcp, google |\n| `gcp.cloud-spanner` | Cloud Spanner | 176×56 | gcp, google |\n| `gcp.firestore` | Firestore | 176×56 | gcp, google |\n| `gcp.bigtable` | Bigtable | 176×56 | gcp, google |\n| `gcp.bigquery` | BigQuery | 176×56 | gcp, google |\n| `gcp.memorystore` | Memorystore | 176×56 | gcp, google |\n| `gcp.vpc` | VPC | 176×56 | gcp, google |\n| `gcp.cloud-load-balancing` | Cloud Load Balancing | 176×56 | gcp, google |\n| `gcp.cloud-cdn` | Cloud CDN | 176×56 | gcp, google |\n| `gcp.cloud-dns` | Cloud DNS | 176×56 | gcp, google |\n| `gcp.pub-sub` | Pub/Sub | 176×56 | gcp, google |\n| `gcp.dataflow` | Dataflow | 176×56 | gcp, google |\n| `gcp.cloud-tasks` | Cloud Tasks | 176×56 | gcp, google |\n| `gcp.iam` | IAM | 176×56 | gcp, google |\n| `gcp.secret-manager` | Secret Manager | 176×56 | gcp, google |\n| `gcp.cloud-kms` | Cloud KMS | 176×56 | gcp, google |\n| `gcp.cloud-monitoring` | Cloud Monitoring | 176×56 | gcp, google |\n| `gcp.vertex-ai` | Vertex AI | 176×56 | gcp, google |\n",
@@ -44,6 +44,8 @@ exports.TOOL_CATALOG = [
44
44
  { name: "delete_data_contract", group: "contracts", scopes: ["requests:delete"], destructive: true },
45
45
  // The safe connection record (no credentials) — readable with either family.
46
46
  { name: "list_connections", group: "connections", scopes: ["requests:read", "scenarios:read"], anyOf: true },
47
+ // The database behind a connection (metadata only) — what a Database Diagram is built from.
48
+ { name: "introspect_database", group: "connections", scopes: ["requests:read", "scenarios:read", "diagrams:write"], anyOf: true },
47
49
  // Documents and new collections → import:write; cURL/.http into an existing
48
50
  // collection → requests:write.
49
51
  { name: "import_content", group: "import", scopes: ["import:write", "requests:write"], anyOf: true },
@@ -72,6 +74,9 @@ exports.TOOL_CATALOG = [
72
74
  { name: "patch_diagram", group: "diagrams", scopes: ["diagrams:write"] },
73
75
  { name: "delete_diagram", group: "diagrams", scopes: ["diagrams:delete"], destructive: true },
74
76
  { name: "share_diagram", group: "diagrams", scopes: ["diagrams:share"] },
77
+ { name: "create_diagram_folder", group: "diagrams", scopes: ["diagrams:write"] },
78
+ { name: "update_diagram_folder", group: "diagrams", scopes: ["diagrams:write"] },
79
+ { name: "delete_diagram_folder", group: "diagrams", scopes: ["diagrams:delete"], destructive: true },
75
80
  ];
76
81
  const toolAvailability = (tokenScopes, allowLocalRun) => {
77
82
  const held = new Set(tokenScopes);