feat(mcp): drawio стадия 3 — высокоуровневые инструменты: drawio_edit_cells, drawio_from_graph, drawio_from_mermaid #425

Open
opened 2026-07-09 23:35:10 +03:00 by agent_vscode · 0 comments
Collaborator

ТЗ: семантические инструменты вместо сырого XML

Зависит от #423 (CRUD-конвейер) и #424 (shape-каталог, elkjs, quality-warnings).

Цель

Сырой XML остаётся escape-hatch, но для 90% случаев модель не должна видеть ни координат, ни style-строк — весь класс ошибок лейаута (налезания, edge сквозь фигуры, кривые интервалы) и иконок (пустые квадраты, перепутанные паттерны) исчезает by construction: эти решения принимает сервер, а не LLM.

Инструменты

1. drawio_edit_cells(pageId, node, operations, baseHash)

ID-based точечные правки вместо пересылки полного XML (референс next-ai-draw-io: они мигрировали на это с {search, replace} — текст-матчинг ломался на порядке атрибутов):

"operations": [
  { "op": "add",    "xml": "<mxCell id=\"n7\" …><mxGeometry …/></mxCell>" },
  { "op": "update", "cellId": "n3", "xml": "<mxCell …новая версия ячейки…/>" },
  { "op": "delete", "cellId": "n5" }   // каскад: дети + все связанные edge
]
  • Сервер: прочитать текущий XML из вложения → применить операции (DOM-правки) → re-lint + quality-warnings → пересобрать .drawio.svg → перезаписать вложение (конвейер #423).
  • delete каскадит на детей контейнера и на edge, у которых ячейка — source/target.
  • baseHash обязателен (как в drawio_update).
  • Стабильные id между правками → осмысленные диффы (так же работает «Update diagram from clipboard» в официальном draw.io: copy сохраняет id, update диффает по ним).

2. drawio_from_graph(pageId, where, graph, direction?, preset?, layout?) — главный инструмент

Модель описывает диаграмму семантически, без координат и style-строк:

{
  "nodes":  [
    { "id": "api",    "label": "API Gateway", "kind": "gateway", "icon": "aws:api_gateway", "group": "vpc1" },
    { "id": "lambda", "label": "Handler",     "kind": "service", "icon": "aws:lambda",      "group": "vpc1" },
    { "id": "db",     "label": "Orders",      "kind": "db",      "icon": "aws:dynamodb" }
  ],
  "groups": [ { "id": "vpc1", "label": "VPC 10.0.0.0/16", "kind": "vpc" } ],
  "edges":  [
    { "from": "api", "to": "lambda", "label": "HTTPS", "kind": "sync" },
    { "from": "lambda", "to": "db", "kind": "async" }
  ],
  "direction": "LR",
  "preset": "default"
}

Серверный конвейер:

  1. Резолв иконок: icon → точная style-строка через shape-index (#424), с автоматически правильным паттерном (AWS service/resource + категорийный fillColor, Azure image-style — таблицы в приложении #424); неизвестный icon → generic-фигура по kind с подписью (пустой квадрат запрещён);
  2. Стили: kind узла → слот палитры пресета, kind edge → стиль линии (таблицы ниже);
  3. Layout: elkjs layered с compound-узлами (группы = контейнеры), размеры из пресета + длины label;
  4. Сборка XML: свой assembler (~300–500 строк TS, правила линтера #423 соблюдаются by construction) → далее конвейер #423 (lint → превью → вложение → узел).

Семантическая палитра узлов (базовая, слоты пресета; пары fill/stroke):

kind fill / stroke Семантика
service #dae8fc / #6c8ebf (синий) сервисы/приложения
db #d5e8d4 / #82b366 (зелёный) БД/хранилища
queue #fff2cc / #d6b656 (жёлтый) очереди/решения
gateway #ffe6cc / #d79b00 (оранжевый) API/шлюзы
error #f8cecc / #b85450 (красный) ошибки/DLQ
external #f5f5f5 / #666666 (серый) внешние системы
security #e1d5e7 / #9673a6 (фиолетовый) auth/безопасность

Стили edge по kind: sync — сплошная; asyncdashed=1; errordashed=1;strokeColor=#DD344C. Группы всегда fillColor=none;container=1;dropTarget=1.

Пресеты: default / dark / colorblind-safe (палитра Okabe-Ito). JSON-данные kind → style, отдельно от кода.

Контроль координат (когда нужен):

  • семантические хинты в graph-JSON: {"layer": 0}, {"sameLayerAs": "db2"}, {"pinned": {"x": 40, "y": 900}} — маппятся на ELK layer/position constraints и fixed-узлы;
  • layout: "none" | "full" | "incremental"incremental обязателен для правки существующих диаграмм: существующие координаты фиксируются (ELK interactive mode), размещаются только новые элементы — полный re-layout снёс бы ручную расстановку человека;
  • точечная доводка — drawio_edit_cells с явным mxGeometry;
  • не-графовые случаи (wireframe/мокап) — сырой XML из #423, by design.

3. drawio_from_mermaid(pageId, where, mermaid) — опционально, после from_graph

Модель пишет Mermaid (LLM делают это очень надёжно) → сервер конвертит в редактируемый drawio. Ограничение: без Electron/draw.io-CLI, значит конвертация только парсером: mermaid-текст → graph-JSON → конвейер from_graph. Начать с flowchart (покрывает большинство вики-случаев); sequence/class — по спросу.

Если парсерный путь окажется дороже пользы — инструмент дропаем: from_graph покрывает те же сценарии, просто чуть многословнее для модели.

Состав конвертера (что готовое, что своё)

Кусок Откуда Лицензия
Layout elkjs (npm, уже в #424) EPL-2.0
Edge-routing вокруг фигур (опц. пост-проход) libavoid-pass.js + WASM из jgraph/drawio-mcp (mcp-tool-server/vendor/libavoid/) Apache-2.0
XML-assembler (graph+координаты → mxCell) свой, ~300–500 строк TS; референсы: autolayout.py из Agents365-ai/drawio-skill (MIT), normalize-diagram-xml.js + shared/mxfile.xsd из jgraph/drawio-mcp
graph-JSON → ELK-JSON маппер свой, ~150–200 строк
Shape-index уже бандлен в #424 Apache-2.0
Пресеты kind→style свои (JSON-данные, таблицы выше)

Готового npm «graph-JSON → drawio» не существует (проверено: единственное похожее — mxgraphdata, мёртвый reader) — но своего кода здесь ~500–700 строк без браузерных/нативных зависимостей.

Где в коде

  • packages/mcp/src/lib/drawio-graph.ts — graph-схема (zod), маппер в ELK, assembler;
  • packages/mcp/src/lib/drawio-presets.ts + packages/mcp/data/drawio-presets.json — палитры;
  • packages/mcp/src/lib/drawio-cell-ops.ts — операции edit_cells с каскадом;
  • packages/mcp/src/tool-specs.ts — три инструмента + роутинг в descriptions: from_mermaid → стандартные типы; from_graph → архитектуры/облака/сети; сырой xml → экзотика/wireframe.

Критерии приёмки

  1. drawio_from_graph на графе 15+ узлов с 2 вложенными группами и AWS-иконками выдаёт диаграмму: 0 lint-ошибок, 0 quality-warnings, все иконки резолвятся (нет пустых квадратов), группы прозрачные, направление соблюдено.
  2. Хинты работают: pinned-узел остаётся на заданных координатах, sameLayerAs-пара — в одном слое.
  3. layout:"incremental" при добавлении узла в диаграмму с ручной расстановкой не меняет координаты существующих ячеек.
  4. drawio_edit_cells: update меняет одну ячейку не трогая остальные; delete контейнера убирает детей и связанные edge; устаревший baseHash → конфликт.
  5. Каждый kind пресетов покрыт снапшот-тестом style-строки; colorblind-safe не содержит проблемных пар цветов.
  6. (Если делаем mermaid) flowchart с ветвлением и подграфом конвертится в валидный drawio, редактируемый в draw.io.

Внешние референсы

Вне скоупа

  • Live-embed/стриминг в редактор, совместное редактирование в реальном времени (паттерны next-ai-draw-io) — отдельный проект, имеет смысл только после стадий 1–3.
  • Специализированные генераторы (sequence из participants/messages, ERD из DDL) — по спросу, отдельными ишью.
# ТЗ: семантические инструменты вместо сырого XML Зависит от #423 (CRUD-конвейер) и #424 (shape-каталог, elkjs, quality-warnings). ## Цель Сырой XML остаётся escape-hatch, но для 90% случаев модель не должна видеть ни координат, ни style-строк — весь класс ошибок лейаута (налезания, edge сквозь фигуры, кривые интервалы) и иконок (пустые квадраты, перепутанные паттерны) исчезает by construction: эти решения принимает сервер, а не LLM. ## Инструменты ### 1. `drawio_edit_cells(pageId, node, operations, baseHash)` ID-based точечные правки вместо пересылки полного XML (референс next-ai-draw-io: они мигрировали на это с `{search, replace}` — текст-матчинг ломался на порядке атрибутов): ```jsonc "operations": [ { "op": "add", "xml": "<mxCell id=\"n7\" …><mxGeometry …/></mxCell>" }, { "op": "update", "cellId": "n3", "xml": "<mxCell …новая версия ячейки…/>" }, { "op": "delete", "cellId": "n5" } // каскад: дети + все связанные edge ] ``` - Сервер: прочитать текущий XML из вложения → применить операции (DOM-правки) → re-lint + quality-warnings → пересобрать `.drawio.svg` → перезаписать вложение (конвейер #423). - `delete` каскадит на детей контейнера и на edge, у которых ячейка — source/target. - `baseHash` обязателен (как в `drawio_update`). - Стабильные id между правками → осмысленные диффы (так же работает «Update diagram from clipboard» в официальном draw.io: copy сохраняет id, update диффает по ним). ### 2. `drawio_from_graph(pageId, where, graph, direction?, preset?, layout?)` — главный инструмент Модель описывает диаграмму семантически, без координат и style-строк: ```jsonc { "nodes": [ { "id": "api", "label": "API Gateway", "kind": "gateway", "icon": "aws:api_gateway", "group": "vpc1" }, { "id": "lambda", "label": "Handler", "kind": "service", "icon": "aws:lambda", "group": "vpc1" }, { "id": "db", "label": "Orders", "kind": "db", "icon": "aws:dynamodb" } ], "groups": [ { "id": "vpc1", "label": "VPC 10.0.0.0/16", "kind": "vpc" } ], "edges": [ { "from": "api", "to": "lambda", "label": "HTTPS", "kind": "sync" }, { "from": "lambda", "to": "db", "kind": "async" } ], "direction": "LR", "preset": "default" } ``` Серверный конвейер: 1. **Резолв иконок**: `icon` → точная style-строка через shape-index (#424), с автоматически правильным паттерном (AWS service/resource + категорийный fillColor, Azure image-style — таблицы в приложении #424); неизвестный `icon` → generic-фигура по `kind` с подписью (пустой квадрат запрещён); 2. **Стили**: `kind` узла → слот палитры пресета, `kind` edge → стиль линии (таблицы ниже); 3. **Layout**: elkjs layered с compound-узлами (группы = контейнеры), размеры из пресета + длины label; 4. **Сборка XML**: свой assembler (~300–500 строк TS, правила линтера #423 соблюдаются by construction) → далее конвейер #423 (lint → превью → вложение → узел). **Семантическая палитра узлов** (базовая, слоты пресета; пары fill/stroke): | kind | fill / stroke | Семантика | |---|---|---| | `service` | `#dae8fc` / `#6c8ebf` (синий) | сервисы/приложения | | `db` | `#d5e8d4` / `#82b366` (зелёный) | БД/хранилища | | `queue` | `#fff2cc` / `#d6b656` (жёлтый) | очереди/решения | | `gateway` | `#ffe6cc` / `#d79b00` (оранжевый) | API/шлюзы | | `error` | `#f8cecc` / `#b85450` (красный) | ошибки/DLQ | | `external` | `#f5f5f5` / `#666666` (серый) | внешние системы | | `security` | `#e1d5e7` / `#9673a6` (фиолетовый) | auth/безопасность | **Стили edge по kind**: `sync` — сплошная; `async` — `dashed=1`; `error` — `dashed=1;strokeColor=#DD344C`. Группы всегда `fillColor=none;container=1;dropTarget=1`. **Пресеты**: `default` / `dark` / `colorblind-safe` (палитра Okabe-Ito). JSON-данные `kind → style`, отдельно от кода. **Контроль координат** (когда нужен): - семантические хинты в graph-JSON: `{"layer": 0}`, `{"sameLayerAs": "db2"}`, `{"pinned": {"x": 40, "y": 900}}` — маппятся на ELK layer/position constraints и fixed-узлы; - `layout: "none" | "full" | "incremental"` — **incremental обязателен для правки существующих диаграмм**: существующие координаты фиксируются (ELK interactive mode), размещаются только новые элементы — полный re-layout снёс бы ручную расстановку человека; - точечная доводка — `drawio_edit_cells` с явным `mxGeometry`; - не-графовые случаи (wireframe/мокап) — сырой XML из #423, by design. ### 3. `drawio_from_mermaid(pageId, where, mermaid)` — опционально, после from_graph Модель пишет Mermaid (LLM делают это очень надёжно) → сервер конвертит в **редактируемый** drawio. Ограничение: **без Electron/draw.io-CLI**, значит конвертация только парсером: mermaid-текст → graph-JSON → конвейер from_graph. Начать с `flowchart` (покрывает большинство вики-случаев); sequence/class — по спросу. Если парсерный путь окажется дороже пользы — инструмент дропаем: `from_graph` покрывает те же сценарии, просто чуть многословнее для модели. ## Состав конвертера (что готовое, что своё) | Кусок | Откуда | Лицензия | |---|---|---| | Layout | elkjs (npm, уже в #424) | EPL-2.0 | | Edge-routing вокруг фигур (опц. пост-проход) | `libavoid-pass.js` + WASM из jgraph/drawio-mcp (`mcp-tool-server/vendor/libavoid/`) | Apache-2.0 | | XML-assembler (graph+координаты → mxCell) | **свой**, ~300–500 строк TS; референсы: `autolayout.py` из Agents365-ai/drawio-skill (MIT), `normalize-diagram-xml.js` + `shared/mxfile.xsd` из jgraph/drawio-mcp | — | | graph-JSON → ELK-JSON маппер | **свой**, ~150–200 строк | — | | Shape-index | уже бандлен в #424 | Apache-2.0 | | Пресеты kind→style | **свои** (JSON-данные, таблицы выше) | — | Готового npm «graph-JSON → drawio» не существует (проверено: единственное похожее — `mxgraphdata`, мёртвый reader) — но своего кода здесь ~500–700 строк без браузерных/нативных зависимостей. ## Где в коде - `packages/mcp/src/lib/drawio-graph.ts` — graph-схема (zod), маппер в ELK, assembler; - `packages/mcp/src/lib/drawio-presets.ts` + `packages/mcp/data/drawio-presets.json` — палитры; - `packages/mcp/src/lib/drawio-cell-ops.ts` — операции edit_cells с каскадом; - `packages/mcp/src/tool-specs.ts` — три инструмента + роутинг в descriptions: `from_mermaid` → стандартные типы; `from_graph` → архитектуры/облака/сети; сырой `xml` → экзотика/wireframe. ## Критерии приёмки 1. `drawio_from_graph` на графе 15+ узлов с 2 вложенными группами и AWS-иконками выдаёт диаграмму: 0 lint-ошибок, 0 quality-warnings, все иконки резолвятся (нет пустых квадратов), группы прозрачные, направление соблюдено. 2. Хинты работают: `pinned`-узел остаётся на заданных координатах, `sameLayerAs`-пара — в одном слое. 3. `layout:"incremental"` при добавлении узла в диаграмму с ручной расстановкой не меняет координаты существующих ячеек. 4. `drawio_edit_cells`: update меняет одну ячейку не трогая остальные; delete контейнера убирает детей и связанные edge; устаревший `baseHash` → конфликт. 5. Каждый `kind` пресетов покрыт снапшот-тестом style-строки; `colorblind-safe` не содержит проблемных пар цветов. 6. (Если делаем mermaid) flowchart с ветвлением и подграфом конвертится в валидный drawio, редактируемый в draw.io. ## Внешние референсы - libavoid-pass + mxfile.xsd + normalize: https://github.com/jgraph/drawio-mcp (Apache-2.0) - graph.json → autolayout pipeline и схема пресетов (`styles/schema.json`): https://github.com/Agents365-ai/drawio-skill (MIT) - ID-based операции + каскадный delete (`applyDiagramOperations`): https://github.com/DayuanJiang/next-ai-draw-io (Apache-2.0) - elkjs (constraints, interactive mode): https://github.com/kieler/elkjs (EPL-2.0) ## Вне скоупа - Live-embed/стриминг в редактор, совместное редактирование в реальном времени (паттерны next-ai-draw-io) — отдельный проект, имеет смысл только после стадий 1–3. - Специализированные генераторы (sequence из participants/messages, ERD из DDL) — по спросу, отдельными ишью.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: vvzvlad/gitmost#425