@retailcrm/embed-ui-v1-endpoint 0.9.23 → 0.9.25

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 (34) hide show
  1. package/README.md +10 -0
  2. package/bin/embed-ui-v1-endpoint.mjs +48 -3
  3. package/docs/README.md +1 -0
  4. package/docs/layout.md +17 -5
  5. package/docs/menu-placements.md +71 -1
  6. package/docs/page-routes.md +24 -2
  7. package/docs/targets/customer-card-communications-after.yml +2 -0
  8. package/docs/targets/customer-card-inwork-after.yml +2 -0
  9. package/docs/targets/customer-card-inwork-before.yml +2 -0
  10. package/docs/targets/customer-card-phone.yml +2 -0
  11. package/docs/targets/order-card-comment-manager-before.yml +2 -0
  12. package/docs/targets/order-card-common-after.yml +2 -0
  13. package/docs/targets/order-card-common-before.yml +2 -0
  14. package/docs/targets/order-card-customer-after.yml +2 -0
  15. package/docs/targets/order-card-customer-before.yml +2 -0
  16. package/docs/targets/order-card-customer-email.yml +2 -0
  17. package/docs/targets/order-card-customer-phone.yml +2 -0
  18. package/docs/targets/order-card-delivery-address.yml +2 -0
  19. package/docs/targets/order-card-delivery-after.yml +2 -0
  20. package/docs/targets/order-card-delivery-before.yml +2 -0
  21. package/docs/targets/order-card-dimensions-before.yml +2 -0
  22. package/docs/targets/order-card-list-after.yml +2 -0
  23. package/docs/targets/order-card-list-before.yml +2 -0
  24. package/docs/targets/order-card-payment-before.yml +2 -0
  25. package/docs/targets/order-card-store-before.yml +2 -0
  26. package/docs/targets/order-mg-delivery-after.yml +2 -0
  27. package/docs/targets/order-mg-delivery-before.yml +2 -0
  28. package/docs/targets/order-mg-list-after.yml +2 -0
  29. package/docs/targets/order-mg-list-before.yml +2 -0
  30. package/docs/targets/order-mg-payment-after.yml +2 -0
  31. package/docs/targets/order-mg-payment-before.yml +2 -0
  32. package/docs/targets.md +15 -2
  33. package/package.json +8 -7
  34. package/templates/skills/embed-ui-v1-endpoint-runtime/SKILL.md.txt +45 -0
package/README.md CHANGED
@@ -41,6 +41,7 @@ runEndpoint(runner)
41
41
  - [`createEndpoint`](./docs/create-endpoint.md) — как вручную создать endpoint с transport и messenger.
42
42
  - [`runEndpoint`](./docs/run-endpoint.md) — как поднять endpoint в точке входа веб-воркера одной строкой.
43
43
  - [`targets` и `defineTarget`](./docs/targets.md) — как типизировать цели виджетов и маршрутизировать их по target.
44
+ - `@retailcrm/embed-ui-v1-components` `docs/profiles/widgets/WidgetComposition.yml` — как оформлять inline UI виджетов и когда уносить сложность в modal/sidebar.
44
45
  - [`menu-placements`](./docs/menu-placements.md) — как описывать меню и пункты навигации для встраиваемых страниц.
45
46
  - [`page-routes`](./docs/page-routes.md) — как связывать page `code`, CRM-маршрут и `definePageRunner`.
46
47
  - [`layout`](./docs/layout.md) — как выбирать паттерны компоновки страниц, `modal sidebar` и `modal window`, и из каких `v1-components` их собирать.
@@ -84,6 +85,15 @@ npx @retailcrm/embed-ui-v1-endpoint init-agents
84
85
  такого блока там ещё нет. С `--force` можно обновить уже существующий блок
85
86
  пакета.
86
87
 
88
+ Для project-level skills можно создать `.agents/skills/embed-ui-v1-endpoint-runtime/SKILL.md`:
89
+
90
+ ```bash
91
+ npx @retailcrm/embed-ui-v1-endpoint init-skills
92
+ ```
93
+
94
+ Skill описывает повторяемый workflow для pages/widgets, runner setup, target selection,
95
+ menu hierarchy, page publishing payloads и публичных границ Host API.
96
+
87
97
  ## Инициализация MCP-конфига
88
98
 
89
99
  Пакет также может сам добавить project-level MCP-настройки в целевой проект:
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
 
3
+ import { fileURLToPath } from 'node:url'
3
4
  import fs from 'node:fs'
4
5
  import path from 'node:path'
5
6
  import process from 'node:process'
@@ -13,6 +14,8 @@ const README_MCP_SECTION_HEADER = '## MCP For AI Assistants: @retailcrm/embed-ui
13
14
  const LEGACY_README_MCP_SECTION_HEADER = '## MCP For AI Assistants'
14
15
  const README_MCP_MARKER = 'embed-ui-v1-endpoint://targets'
15
16
  const MCP_SERVER_NAME = 'retailcrm-embed-ui-v1-endpoint'
17
+ const SKILL_NAME = 'embed-ui-v1-endpoint-runtime'
18
+ const SKILL_TEMPLATE_PATH = `templates/skills/${SKILL_NAME}/SKILL.md.txt`
16
19
  const MCP_BIN_NAME = process.platform === 'win32' ? 'embed-ui-v1-endpoint-mcp.cmd' : 'embed-ui-v1-endpoint-mcp'
17
20
  const RELATIVE_MCP_BIN_PATH = `./node_modules/.bin/${MCP_BIN_NAME}`
18
21
  const CLAUDE_PROJECT_MCP_BIN_PATH = `\${CLAUDE_PROJECT_DIR:-.}/node_modules/.bin/${MCP_BIN_NAME}`
@@ -49,6 +52,7 @@ const MCP_CLIENT_CONFIGS = {
49
52
  const HELP_TEXT = `Usage:
50
53
  npx ${PACKAGE_NAME} init-agents [target] [options]
51
54
  npx ${PACKAGE_NAME} init-config [target] [options]
55
+ npx ${PACKAGE_NAME} init-skills [target] [options]
52
56
 
53
57
  Options:
54
58
  -f, --force Replace existing managed sections and MCP server entries
@@ -58,6 +62,7 @@ Options:
58
62
 
59
63
  Examples:
60
64
  npx ${PACKAGE_NAME} init-agents
65
+ npx ${PACKAGE_NAME} init-skills
61
66
  npx ${PACKAGE_NAME} init-agents ./my-project
62
67
  npx ${PACKAGE_NAME} init-agents --force
63
68
  npx ${PACKAGE_NAME} init-config ./my-project
@@ -75,6 +80,10 @@ const printMcpNotice = (message) => {
75
80
  console.log(`MCP: ${message}`)
76
81
  }
77
82
 
83
+ const packageRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..')
84
+
85
+ const createSkill = () => fs.readFileSync(path.join(packageRoot, SKILL_TEMPLATE_PATH), 'utf8')
86
+
78
87
  const parseArgs = (argv) => {
79
88
  const options = {
80
89
  command: null,
@@ -157,9 +166,11 @@ When working with \`${PACKAGE_NAME}\` in this project:
157
166
  5. When the task involves widget targets, target placement, target contexts, target metadata, or choosing a target, use the package MCP server if it is available.
158
167
  6. First read \`embed-ui-v1-endpoint://targets\` to discover available target profiles.
159
168
  7. Then read the relevant \`embed-ui-v1-endpoint://targets/<encoded-target>\` resource before answering or changing code related to that target.
160
- 8. A project \`.mcp.json\` may require restarting or reconnecting the AI client before MCP resources appear in the current session.
161
- 9. If MCP resources are not available, use the generated YAML profiles from \`./node_modules/${PACKAGE_NAME}/docs/targets/*.yml\` as the fallback source.
162
- 10. Prefer target profiles over guessing target placement, contexts, or semantic intent from names alone.
169
+ 8. For widget UI composition, keep inline target content compact: prefer \`UiToolbarButton\`, \`UiToolbarLink\`, short text, and icons; move complex UI into \`UiModalSidebar\` or \`UiModalWindow\`.
170
+ 9. If \`@retailcrm/embed-ui-v1-components\` is installed, read its widget composition docs before building widget UI.
171
+ 10. A project \`.mcp.json\` may require restarting or reconnecting the AI client before MCP resources appear in the current session.
172
+ 11. If MCP resources are not available, use the generated YAML profiles from \`./node_modules/${PACKAGE_NAME}/docs/targets/*.yml\` as the fallback source.
173
+ 12. Prefer target profiles over guessing target placement, contexts, or semantic intent from names alone.
163
174
 
164
175
  Suggested MCP stdio server configuration:
165
176
 
@@ -455,6 +466,35 @@ const initAgents = (target, force) => {
455
466
  console.log(`The ${PACKAGE_NAME} instructions were appended to the end of the file.`)
456
467
  }
457
468
 
469
+ const initSkills = (target, options) => {
470
+ if (!fs.existsSync(target)) {
471
+ throw new Error(`Target path does not exist: ${target}`)
472
+ }
473
+
474
+ const stat = fs.statSync(target)
475
+
476
+ if (!stat.isDirectory()) {
477
+ throw new Error(`Target path is not a directory: ${target}`)
478
+ }
479
+
480
+ const skillPath = path.join(target, '.agents', 'skills', SKILL_NAME, 'SKILL.md')
481
+ const fileExists = fs.existsSync(skillPath)
482
+
483
+ if (fileExists && !options.force) {
484
+ console.log(`${skillPath} already exists`)
485
+ console.log('Nothing was changed. Re-run with --force to refresh that skill.')
486
+ return
487
+ }
488
+
489
+ if (!options.dryRun) {
490
+ fs.mkdirSync(path.dirname(skillPath), { recursive: true })
491
+ fs.writeFileSync(skillPath, createSkill(), 'utf8')
492
+ }
493
+
494
+ const action = fileExists ? 'updated' : 'created'
495
+ console.log(`SKILL: ${options.dryRun ? `would ${action}` : action} ${skillPath}`)
496
+ }
497
+
458
498
  const writeMcpServerConfig = (target, relativePath, rootField, options, serverConfig) => {
459
499
  const filePath = path.join(target, relativePath)
460
500
  const fileExists = fs.existsSync(filePath)
@@ -571,6 +611,11 @@ const main = () => {
571
611
  return
572
612
  }
573
613
 
614
+ if (options.command === 'init-skills') {
615
+ initSkills(options.target, options)
616
+ return
617
+ }
618
+
574
619
  throw new Error(`Unknown command: ${options.command}`)
575
620
  } catch (error) {
576
621
  console.error(error instanceof Error ? error.message : String(error))
package/docs/README.md CHANGED
@@ -14,6 +14,7 @@
14
14
 
15
15
  - [`targets` и `defineTarget`](./targets.md) — типизированные цели для виджетов.
16
16
  - [`targets/*.yml`](./targets/) — сгенерированные AI-friendly описания встроенных widget targets на английском.
17
+ - `@retailcrm/embed-ui-v1-components` `docs/profiles/widgets/WidgetComposition.yml` — как оформлять inline UI виджетов и когда уносить сложность в modal/sidebar.
17
18
  - MCP-сервер `embed-ui-v1-endpoint-mcp` — поставляемый stdio server, который отдаёт `targets/*.yml` как MCP resources.
18
19
  - [`menu-placements`](./menu-placements.md) — как описывать меню и пункты навигации, из которых открываются встраиваемые страницы.
19
20
  - [`page-routes`](./page-routes.md) — как связывать page `code`, CRM-маршрут и `definePageRunner`.
package/docs/layout.md CHANGED
@@ -31,6 +31,8 @@
31
31
  - Для контентных подложек базовое правило такое:
32
32
  - отступ от верхнего края подложки: `24px`;
33
33
  - отступы от левого, правого и нижнего края: `32px`.
34
+ - Эти отступы относятся к белой контентной подложке, а не к корневому wrapper страницы.
35
+ - Корневой wrapper страницы не должен дублировать padding подложки; внешнюю рамку страницы задаёт CRM host layout.
34
36
  - Между смысловыми блоками оставляйте заметную дистанцию, а не склеивайте их.
35
37
 
36
38
  ### Заголовок страницы
@@ -47,10 +49,14 @@
47
49
 
48
50
  ### Кнопки
49
51
 
50
- - На странице допускается одна основная `Default Primary` кнопка.
51
- - Отдельно может быть одна `Success Primary`, если сценарий этого требует.
52
- - Остальные действия рекомендуется оформлять через `Default Secondary`, `Default Tertiary`, `Success Secondary` и похожие менее доминирующие варианты.
53
- - Если действий много, одно оставляют главным, а остальные уводят во вторичный слой или dropdown.
52
+ - В рамках всей страницы допускается максимум по одной page-level `primary`-кнопке каждого варианта: `Success Primary`, `Default Primary` и `Danger Primary`.
53
+ - `Success Primary` главное call-to-action страницы: действие, которое создаёт или фиксирует результат, например `Сохранить`, `Применить`, `Создать`. Обычно оно находится в `UiPageFooter`.
54
+ - Если важное действие не является главным commit-действием, используйте `Default Primary`.
55
+ - `Danger Primary` допустим только для одного критичного деструктивного действия.
56
+ - Если важных действий несколько, выберите главное и оформите его как `Success Primary`; остальные переводите в `Default Primary`, `Default Secondary`, `Default Tertiary`, `Success Secondary` или другой менее доминирующий вариант по смыслу.
57
+ - `UiPageHeader` и `UiPageFooter` относятся к одному page-level scope: `UiPageFooter` не сбрасывает лимит сам по себе.
58
+ - Только `UiCollapseBox` с собственным footer создаёт локальный scope: внутри каждого блока может быть одна `Default Primary` для главного действия этой секции.
59
+ - Если действий много, оставьте видимыми только действительно важные, а остальные уводите во вторичный слой или dropdown.
54
60
 
55
61
  Типичная компонентная основа:
56
62
 
@@ -61,6 +67,7 @@
61
67
 
62
68
  - Основной контент страницы обычно расположен на белых подложках.
63
69
  - Подложка должна собирать один смысловой блок, а не случайный набор элементов.
70
+ - Padding `24px 32px 32px` ставится на саму подложку с контентом, а не на общий wrapper страницы.
64
71
  - Если на экране есть несколько независимых смысловых секций, предпочтительнее использовать несколько подложек, чем одну перегруженную.
65
72
 
66
73
  ## 1. Страница со списком сущностей
@@ -99,6 +106,8 @@
99
106
 
100
107
  - Таблица является главным содержимым списка.
101
108
  - Она может листаться, пагинироваться и поддерживать выгрузку.
109
+ - `UiTable` не нужно заворачивать в дополнительную белую подложку: таблица сама задаёт табличную поверхность, границы и внутренние отступы.
110
+ - Wrapper вокруг таблицы допустим только как layout/scroll/width container без собственной белой карточки и без padding подложки.
102
111
  - Не следует смешивать в одном списочном экране слишком много “карточной” логики; список должен оставаться в первую очередь инструментом поиска и просмотра.
103
112
 
104
113
  Типичная компонентная основа:
@@ -207,6 +216,7 @@
207
216
  - Если на странице используются `Collapse`-блоки, дополнительная общая белая подложка вокруг них обычно не нужна.
208
217
  - Если подложка видна только ради пары collapse-блоков, от неё следует отказаться.
209
218
  - Обычно и общая нижняя панель сохранения не нужна, потому что каждый блок сохраняется отдельно.
219
+ - Каждый `UiCollapseBox` с footer работает как локальная “мини-страница”: в его footer можно использовать одну `Default Primary` кнопку для главного действия секции, а остальные действия оформлять менее доминирующе.
210
220
 
211
221
  ### Типичный состав
212
222
 
@@ -247,6 +257,7 @@
247
257
  - `UiModalSidebar` как контейнер `modal sidebar`.
248
258
  - Внутри: обычные form/content primitives из `v1-components`.
249
259
  - В `footer`: `UiButton` для сохранения, закрытия и удаления.
260
+ - Главное действие сохранения или применения в `footer` обычно оформляется как `Success Primary`; соседние действия должны быть менее доминирующими, если они не являются самостоятельным `Default Primary` или `Danger Primary` по смыслу.
250
261
 
251
262
  ### Типичный состав
252
263
 
@@ -329,8 +340,9 @@
329
340
  2. Это список, карточка, карточка с колонками или collapse-настройки?
330
341
  3. Нужны ли tabs, или блоки следует оставить на одном полотне?
331
342
  4. Нужна ли общая панель сохранения, или каждый блок должен сохраняться отдельно?
332
- 5. Не перегружен ли экран количеством primary-действий?
343
+ 5. Есть ли на странице не больше одного page-level `primary`-действия каждого варианта, а дополнительные `Default Primary` находятся только внутри отдельных `UiCollapseBox`?
333
344
  6. Держатся ли отступы и расстояния сетки `4px`?
345
+ 7. Не продублирован ли padding контентной подложки на корневом wrapper страницы?
334
346
 
335
347
  ---
336
348
 
@@ -29,6 +29,76 @@
29
29
  | `route` | Имя или путь CRM-маршрута, если пункт открывается через маршрутизацию host-части. |
30
30
  | `visibility` | Условия показа: права, настройки, тариф, доступность фичи. |
31
31
 
32
+ ## Manifest `pages`
33
+
34
+ В `extensionrc.json` и payload для RetailCRM API страницы нужно описывать объектами `ConfigurationPage`,
35
+ а не строками. Строковый список page codes достаточен только для runtime runner map на фронтенде; backend API
36
+ и меню страницы ожидают метаданные пункта меню.
37
+
38
+ Минимальная рабочая форма:
39
+
40
+ ```json
41
+ {
42
+ "pages": [
43
+ {
44
+ "code": "orders-dashboard",
45
+ "menu": "activity_main_menu",
46
+ "parentMenuItemCode": "orders",
47
+ "menuItemOrdering": 100,
48
+ "menuItemTitle": {
49
+ "ru": "Заказы",
50
+ "en": "Orders",
51
+ "es": "Pedidos"
52
+ },
53
+ "pageHelpLink": null
54
+ }
55
+ ]
56
+ }
57
+ ```
58
+
59
+ `menu` обязателен для опубликованной страницы: без него backend не сможет открыть route вида
60
+ `/modules/<module-code>/<page-code>`. Для страниц в разделе настроек обычно используется
61
+ `menu: "private_main_menu"` и `parentMenuItemCode: "settings"`. Для страниц в разделе продаж используйте
62
+ `menu: "activity_main_menu"` и соответствующий parent menu item, например `orders`.
63
+
64
+ ## Payload публикации
65
+
66
+ При обновлении уже установленного расширения синхронизируйте существующий integration module через
67
+ `/api/v5/integration-modules/{code}/edit`, а не создавайте новый инстанс регистрации. В payload страницы
68
+ должны находиться внутри `integrationModule.integrations.embedJs.pages`:
69
+
70
+ ```json
71
+ {
72
+ "integrationModule": {
73
+ "clientId": "client-id-xxx",
74
+ "integrations": {
75
+ "embedJs": {
76
+ "entrypoint": "https://example.test/extension/demo/script",
77
+ "stylesheet": "https://example.test/extension/demo/stylesheet",
78
+ "runner": "demo",
79
+ "pages": [
80
+ {
81
+ "code": "orders-dashboard",
82
+ "menu": "activity_main_menu",
83
+ "parentMenuItemCode": "orders",
84
+ "menuItemOrdering": 100,
85
+ "menuItemTitle": {
86
+ "ru": "Заказы",
87
+ "en": "Orders",
88
+ "es": "Pedidos"
89
+ },
90
+ "pageHelpLink": null
91
+ }
92
+ ]
93
+ }
94
+ }
95
+ }
96
+ }
97
+ ```
98
+
99
+ Если локальный API client не знает DTO для расширенного payload, используйте поддержанный custom/request
100
+ method с обычным JSON-объектом вместо добавления локального DTO, который serializer не умеет обрабатывать.
101
+
32
102
  ## Пример справочника меню
33
103
 
34
104
  Конкретные `placement`, `item code` и `route` нужно брать из host/manifest расширения.
@@ -66,4 +136,4 @@ const pageRunner = definePageRunner({
66
136
  - [`definePageRunner`](./define-page-runner.md) — как встраиваемая страница получает `code`.
67
137
  - [`targets`](./targets.md) — точки встраивания виджетов, не пунктов меню.
68
138
  - [`layout`](./layout.md) — когда делать полноценную страницу, а когда `modal sidebar` или `modal window`.
69
- - [`UiMenuItem`](../../v1-components/docs/profiles/UiMenuItem.yml) — компонент строки меню внутри UI расширения.
139
+ - `@retailcrm/embed-ui-v1-components` `docs/profiles/components/UiMenuItem.yml` — компонент строки меню внутри UI расширения.
@@ -7,6 +7,11 @@
7
7
  host/manifest конкретного расширения, поэтому его нужно хранить в справочнике проекта рядом с кодом
8
8
  расширения.
9
9
 
10
+ В runtime-коде `definePageRunner` сопоставляет page `code` с Vue-компонентом. В `extensionrc.json` этот же
11
+ page `code` нужно описывать объектом manifest `pages[]` с `menu` и, обычно, `menuItemTitle`. Не используйте
12
+ строковую форму `pages: ["orders-dashboard"]` для публикации через RetailCRM API: backend ожидает
13
+ `ConfigurationPage` object, а страница без `menu` не откроется по route `/modules/<module-code>/<page-code>`.
14
+
10
15
  ## Что такое `page code`
11
16
 
12
17
  `page code` — стабильный идентификатор встраиваемой страницы внутри расширения.
@@ -59,6 +64,23 @@ console.log(settings['system.routing'].routes)
59
64
  | `integration-settings` | `embed.page.integration_settings` | `{}` | `settings / integration-settings` | `IntegrationSettingsPage.vue` |
60
65
  | `customer-tools` | `embed.page.customer_tools` | `{ customerId }` | `customer/card:actions / customer-tools` | `CustomerToolsPage.vue` |
61
66
 
67
+ Пример manifest-записи для страницы:
68
+
69
+ ```json
70
+ {
71
+ "code": "orders-dashboard",
72
+ "menu": "activity_main_menu",
73
+ "parentMenuItemCode": "orders",
74
+ "menuItemOrdering": 100,
75
+ "menuItemTitle": {
76
+ "ru": "Заказы",
77
+ "en": "Orders",
78
+ "es": "Pedidos"
79
+ },
80
+ "pageHelpLink": null
81
+ }
82
+ ```
83
+
62
84
  ## Переход на CRM-маршрут
63
85
 
64
86
  Если странице нужен переход на другой CRM-маршрут, используйте host API, а не прямую сборку URL.
@@ -76,5 +98,5 @@ const openSettings = (host: HostApi) => {
76
98
 
77
99
  - [`menu-placements`](./menu-placements.md) — как связать пункт меню, page `code` и маршрут.
78
100
  - [`definePageRunner`](./define-page-runner.md) — как page `code` попадает в компонент.
79
- - [`settings context`](../../v1-contexts/docs/ru/CONCEPT.md) — общий принцип работы контекстов.
80
- - [`HostApi`](../../v1-types/host.d.ts) — публичный тип host API с `goTo`.
101
+ - `@retailcrm/embed-ui-v1-contexts` `docs/ru/CONCEPT.md` — общий принцип работы контекстов.
102
+ - `@retailcrm/embed-ui-v1-types` `host.d.ts` — публичный тип host API с `goTo`.
@@ -56,6 +56,8 @@ avoid_when:
56
56
 
57
57
  ai_notes:
58
58
  - "Use the target id as the runner registration key."
59
+ - "Keep UI rendered directly in the widget target compact and predictable: prefer UiToolbarButton, UiToolbarLink, short text, and icons."
60
+ - "Move complex widget UI such as forms, tables, maps, filters, summaries, and multi-step flows into UiModalSidebar or UiModalWindow."
59
61
  - "Use targets[target].contexts as the source of truth for context availability."
60
62
  - "Read linked context_resources, action_resources, and custom_context_resources before reasoning about fields, mutations, or custom data."
61
63
  - "Do not infer context field shape from the target id, page name, or widget placement."
@@ -56,6 +56,8 @@ avoid_when:
56
56
 
57
57
  ai_notes:
58
58
  - "Use the target id as the runner registration key."
59
+ - "Keep UI rendered directly in the widget target compact and predictable: prefer UiToolbarButton, UiToolbarLink, short text, and icons."
60
+ - "Move complex widget UI such as forms, tables, maps, filters, summaries, and multi-step flows into UiModalSidebar or UiModalWindow."
59
61
  - "Use targets[target].contexts as the source of truth for context availability."
60
62
  - "Read linked context_resources, action_resources, and custom_context_resources before reasoning about fields, mutations, or custom data."
61
63
  - "Do not infer context field shape from the target id, page name, or widget placement."
@@ -56,6 +56,8 @@ avoid_when:
56
56
 
57
57
  ai_notes:
58
58
  - "Use the target id as the runner registration key."
59
+ - "Keep UI rendered directly in the widget target compact and predictable: prefer UiToolbarButton, UiToolbarLink, short text, and icons."
60
+ - "Move complex widget UI such as forms, tables, maps, filters, summaries, and multi-step flows into UiModalSidebar or UiModalWindow."
59
61
  - "Use targets[target].contexts as the source of truth for context availability."
60
62
  - "Read linked context_resources, action_resources, and custom_context_resources before reasoning about fields, mutations, or custom data."
61
63
  - "Do not infer context field shape from the target id, page name, or widget placement."
@@ -59,6 +59,8 @@ avoid_when:
59
59
 
60
60
  ai_notes:
61
61
  - "Use the target id as the runner registration key."
62
+ - "Keep UI rendered directly in the widget target compact and predictable: prefer UiToolbarButton, UiToolbarLink, short text, and icons."
63
+ - "Move complex widget UI such as forms, tables, maps, filters, summaries, and multi-step flows into UiModalSidebar or UiModalWindow."
62
64
  - "Use targets[target].contexts as the source of truth for context availability."
63
65
  - "Read linked context_resources, action_resources, and custom_context_resources before reasoning about fields, mutations, or custom data."
64
66
  - "Do not infer context field shape from the target id, page name, or widget placement."
@@ -62,6 +62,8 @@ avoid_when:
62
62
 
63
63
  ai_notes:
64
64
  - "Use the target id as the runner registration key."
65
+ - "Keep UI rendered directly in the widget target compact and predictable: prefer UiToolbarButton, UiToolbarLink, short text, and icons."
66
+ - "Move complex widget UI such as forms, tables, maps, filters, summaries, and multi-step flows into UiModalSidebar or UiModalWindow."
65
67
  - "Use targets[target].contexts as the source of truth for context availability."
66
68
  - "Read linked context_resources, action_resources, and custom_context_resources before reasoning about fields, mutations, or custom data."
67
69
  - "Do not infer context field shape from the target id, page name, or widget placement."
@@ -62,6 +62,8 @@ avoid_when:
62
62
 
63
63
  ai_notes:
64
64
  - "Use the target id as the runner registration key."
65
+ - "Keep UI rendered directly in the widget target compact and predictable: prefer UiToolbarButton, UiToolbarLink, short text, and icons."
66
+ - "Move complex widget UI such as forms, tables, maps, filters, summaries, and multi-step flows into UiModalSidebar or UiModalWindow."
65
67
  - "Use targets[target].contexts as the source of truth for context availability."
66
68
  - "Read linked context_resources, action_resources, and custom_context_resources before reasoning about fields, mutations, or custom data."
67
69
  - "Do not infer context field shape from the target id, page name, or widget placement."
@@ -62,6 +62,8 @@ avoid_when:
62
62
 
63
63
  ai_notes:
64
64
  - "Use the target id as the runner registration key."
65
+ - "Keep UI rendered directly in the widget target compact and predictable: prefer UiToolbarButton, UiToolbarLink, short text, and icons."
66
+ - "Move complex widget UI such as forms, tables, maps, filters, summaries, and multi-step flows into UiModalSidebar or UiModalWindow."
65
67
  - "Use targets[target].contexts as the source of truth for context availability."
66
68
  - "Read linked context_resources, action_resources, and custom_context_resources before reasoning about fields, mutations, or custom data."
67
69
  - "Do not infer context field shape from the target id, page name, or widget placement."
@@ -62,6 +62,8 @@ avoid_when:
62
62
 
63
63
  ai_notes:
64
64
  - "Use the target id as the runner registration key."
65
+ - "Keep UI rendered directly in the widget target compact and predictable: prefer UiToolbarButton, UiToolbarLink, short text, and icons."
66
+ - "Move complex widget UI such as forms, tables, maps, filters, summaries, and multi-step flows into UiModalSidebar or UiModalWindow."
65
67
  - "Use targets[target].contexts as the source of truth for context availability."
66
68
  - "Read linked context_resources, action_resources, and custom_context_resources before reasoning about fields, mutations, or custom data."
67
69
  - "Do not infer context field shape from the target id, page name, or widget placement."
@@ -62,6 +62,8 @@ avoid_when:
62
62
 
63
63
  ai_notes:
64
64
  - "Use the target id as the runner registration key."
65
+ - "Keep UI rendered directly in the widget target compact and predictable: prefer UiToolbarButton, UiToolbarLink, short text, and icons."
66
+ - "Move complex widget UI such as forms, tables, maps, filters, summaries, and multi-step flows into UiModalSidebar or UiModalWindow."
65
67
  - "Use targets[target].contexts as the source of truth for context availability."
66
68
  - "Read linked context_resources, action_resources, and custom_context_resources before reasoning about fields, mutations, or custom data."
67
69
  - "Do not infer context field shape from the target id, page name, or widget placement."
@@ -62,6 +62,8 @@ avoid_when:
62
62
 
63
63
  ai_notes:
64
64
  - "Use the target id as the runner registration key."
65
+ - "Keep UI rendered directly in the widget target compact and predictable: prefer UiToolbarButton, UiToolbarLink, short text, and icons."
66
+ - "Move complex widget UI such as forms, tables, maps, filters, summaries, and multi-step flows into UiModalSidebar or UiModalWindow."
65
67
  - "Use targets[target].contexts as the source of truth for context availability."
66
68
  - "Read linked context_resources, action_resources, and custom_context_resources before reasoning about fields, mutations, or custom data."
67
69
  - "Do not infer context field shape from the target id, page name, or widget placement."
@@ -62,6 +62,8 @@ avoid_when:
62
62
 
63
63
  ai_notes:
64
64
  - "Use the target id as the runner registration key."
65
+ - "Keep UI rendered directly in the widget target compact and predictable: prefer UiToolbarButton, UiToolbarLink, short text, and icons."
66
+ - "Move complex widget UI such as forms, tables, maps, filters, summaries, and multi-step flows into UiModalSidebar or UiModalWindow."
65
67
  - "Use targets[target].contexts as the source of truth for context availability."
66
68
  - "Read linked context_resources, action_resources, and custom_context_resources before reasoning about fields, mutations, or custom data."
67
69
  - "Do not infer context field shape from the target id, page name, or widget placement."
@@ -62,6 +62,8 @@ avoid_when:
62
62
 
63
63
  ai_notes:
64
64
  - "Use the target id as the runner registration key."
65
+ - "Keep UI rendered directly in the widget target compact and predictable: prefer UiToolbarButton, UiToolbarLink, short text, and icons."
66
+ - "Move complex widget UI such as forms, tables, maps, filters, summaries, and multi-step flows into UiModalSidebar or UiModalWindow."
65
67
  - "Use targets[target].contexts as the source of truth for context availability."
66
68
  - "Read linked context_resources, action_resources, and custom_context_resources before reasoning about fields, mutations, or custom data."
67
69
  - "Do not infer context field shape from the target id, page name, or widget placement."
@@ -62,6 +62,8 @@ avoid_when:
62
62
 
63
63
  ai_notes:
64
64
  - "Use the target id as the runner registration key."
65
+ - "Keep UI rendered directly in the widget target compact and predictable: prefer UiToolbarButton, UiToolbarLink, short text, and icons."
66
+ - "Move complex widget UI such as forms, tables, maps, filters, summaries, and multi-step flows into UiModalSidebar or UiModalWindow."
65
67
  - "Use targets[target].contexts as the source of truth for context availability."
66
68
  - "Read linked context_resources, action_resources, and custom_context_resources before reasoning about fields, mutations, or custom data."
67
69
  - "Do not infer context field shape from the target id, page name, or widget placement."
@@ -62,6 +62,8 @@ avoid_when:
62
62
 
63
63
  ai_notes:
64
64
  - "Use the target id as the runner registration key."
65
+ - "Keep UI rendered directly in the widget target compact and predictable: prefer UiToolbarButton, UiToolbarLink, short text, and icons."
66
+ - "Move complex widget UI such as forms, tables, maps, filters, summaries, and multi-step flows into UiModalSidebar or UiModalWindow."
65
67
  - "Use targets[target].contexts as the source of truth for context availability."
66
68
  - "Read linked context_resources, action_resources, and custom_context_resources before reasoning about fields, mutations, or custom data."
67
69
  - "Do not infer context field shape from the target id, page name, or widget placement."
@@ -62,6 +62,8 @@ avoid_when:
62
62
 
63
63
  ai_notes:
64
64
  - "Use the target id as the runner registration key."
65
+ - "Keep UI rendered directly in the widget target compact and predictable: prefer UiToolbarButton, UiToolbarLink, short text, and icons."
66
+ - "Move complex widget UI such as forms, tables, maps, filters, summaries, and multi-step flows into UiModalSidebar or UiModalWindow."
65
67
  - "Use targets[target].contexts as the source of truth for context availability."
66
68
  - "Read linked context_resources, action_resources, and custom_context_resources before reasoning about fields, mutations, or custom data."
67
69
  - "Do not infer context field shape from the target id, page name, or widget placement."
@@ -62,6 +62,8 @@ avoid_when:
62
62
 
63
63
  ai_notes:
64
64
  - "Use the target id as the runner registration key."
65
+ - "Keep UI rendered directly in the widget target compact and predictable: prefer UiToolbarButton, UiToolbarLink, short text, and icons."
66
+ - "Move complex widget UI such as forms, tables, maps, filters, summaries, and multi-step flows into UiModalSidebar or UiModalWindow."
65
67
  - "Use targets[target].contexts as the source of truth for context availability."
66
68
  - "Read linked context_resources, action_resources, and custom_context_resources before reasoning about fields, mutations, or custom data."
67
69
  - "Do not infer context field shape from the target id, page name, or widget placement."
@@ -62,6 +62,8 @@ avoid_when:
62
62
 
63
63
  ai_notes:
64
64
  - "Use the target id as the runner registration key."
65
+ - "Keep UI rendered directly in the widget target compact and predictable: prefer UiToolbarButton, UiToolbarLink, short text, and icons."
66
+ - "Move complex widget UI such as forms, tables, maps, filters, summaries, and multi-step flows into UiModalSidebar or UiModalWindow."
65
67
  - "Use targets[target].contexts as the source of truth for context availability."
66
68
  - "Read linked context_resources, action_resources, and custom_context_resources before reasoning about fields, mutations, or custom data."
67
69
  - "Do not infer context field shape from the target id, page name, or widget placement."
@@ -62,6 +62,8 @@ avoid_when:
62
62
 
63
63
  ai_notes:
64
64
  - "Use the target id as the runner registration key."
65
+ - "Keep UI rendered directly in the widget target compact and predictable: prefer UiToolbarButton, UiToolbarLink, short text, and icons."
66
+ - "Move complex widget UI such as forms, tables, maps, filters, summaries, and multi-step flows into UiModalSidebar or UiModalWindow."
65
67
  - "Use targets[target].contexts as the source of truth for context availability."
66
68
  - "Read linked context_resources, action_resources, and custom_context_resources before reasoning about fields, mutations, or custom data."
67
69
  - "Do not infer context field shape from the target id, page name, or widget placement."
@@ -62,6 +62,8 @@ avoid_when:
62
62
 
63
63
  ai_notes:
64
64
  - "Use the target id as the runner registration key."
65
+ - "Keep UI rendered directly in the widget target compact and predictable: prefer UiToolbarButton, UiToolbarLink, short text, and icons."
66
+ - "Move complex widget UI such as forms, tables, maps, filters, summaries, and multi-step flows into UiModalSidebar or UiModalWindow."
65
67
  - "Use targets[target].contexts as the source of truth for context availability."
66
68
  - "Read linked context_resources, action_resources, and custom_context_resources before reasoning about fields, mutations, or custom data."
67
69
  - "Do not infer context field shape from the target id, page name, or widget placement."
@@ -62,6 +62,8 @@ avoid_when:
62
62
 
63
63
  ai_notes:
64
64
  - "Use the target id as the runner registration key."
65
+ - "Keep UI rendered directly in the widget target compact and predictable: prefer UiToolbarButton, UiToolbarLink, short text, and icons."
66
+ - "Move complex widget UI such as forms, tables, maps, filters, summaries, and multi-step flows into UiModalSidebar or UiModalWindow."
65
67
  - "Use targets[target].contexts as the source of truth for context availability."
66
68
  - "Read linked context_resources, action_resources, and custom_context_resources before reasoning about fields, mutations, or custom data."
67
69
  - "Do not infer context field shape from the target id, page name, or widget placement."
@@ -62,6 +62,8 @@ avoid_when:
62
62
 
63
63
  ai_notes:
64
64
  - "Use the target id as the runner registration key."
65
+ - "Keep UI rendered directly in the widget target compact and predictable: prefer UiToolbarButton, UiToolbarLink, short text, and icons."
66
+ - "Move complex widget UI such as forms, tables, maps, filters, summaries, and multi-step flows into UiModalSidebar or UiModalWindow."
65
67
  - "Use targets[target].contexts as the source of truth for context availability."
66
68
  - "Read linked context_resources, action_resources, and custom_context_resources before reasoning about fields, mutations, or custom data."
67
69
  - "Do not infer context field shape from the target id, page name, or widget placement."
@@ -62,6 +62,8 @@ avoid_when:
62
62
 
63
63
  ai_notes:
64
64
  - "Use the target id as the runner registration key."
65
+ - "Keep UI rendered directly in the widget target compact and predictable: prefer UiToolbarButton, UiToolbarLink, short text, and icons."
66
+ - "Move complex widget UI such as forms, tables, maps, filters, summaries, and multi-step flows into UiModalSidebar or UiModalWindow."
65
67
  - "Use targets[target].contexts as the source of truth for context availability."
66
68
  - "Read linked context_resources, action_resources, and custom_context_resources before reasoning about fields, mutations, or custom data."
67
69
  - "Do not infer context field shape from the target id, page name, or widget placement."
@@ -62,6 +62,8 @@ avoid_when:
62
62
 
63
63
  ai_notes:
64
64
  - "Use the target id as the runner registration key."
65
+ - "Keep UI rendered directly in the widget target compact and predictable: prefer UiToolbarButton, UiToolbarLink, short text, and icons."
66
+ - "Move complex widget UI such as forms, tables, maps, filters, summaries, and multi-step flows into UiModalSidebar or UiModalWindow."
65
67
  - "Use targets[target].contexts as the source of truth for context availability."
66
68
  - "Read linked context_resources, action_resources, and custom_context_resources before reasoning about fields, mutations, or custom data."
67
69
  - "Do not infer context field shape from the target id, page name, or widget placement."
@@ -62,6 +62,8 @@ avoid_when:
62
62
 
63
63
  ai_notes:
64
64
  - "Use the target id as the runner registration key."
65
+ - "Keep UI rendered directly in the widget target compact and predictable: prefer UiToolbarButton, UiToolbarLink, short text, and icons."
66
+ - "Move complex widget UI such as forms, tables, maps, filters, summaries, and multi-step flows into UiModalSidebar or UiModalWindow."
65
67
  - "Use targets[target].contexts as the source of truth for context availability."
66
68
  - "Read linked context_resources, action_resources, and custom_context_resources before reasoning about fields, mutations, or custom data."
67
69
  - "Do not infer context field shape from the target id, page name, or widget placement."
@@ -62,6 +62,8 @@ avoid_when:
62
62
 
63
63
  ai_notes:
64
64
  - "Use the target id as the runner registration key."
65
+ - "Keep UI rendered directly in the widget target compact and predictable: prefer UiToolbarButton, UiToolbarLink, short text, and icons."
66
+ - "Move complex widget UI such as forms, tables, maps, filters, summaries, and multi-step flows into UiModalSidebar or UiModalWindow."
65
67
  - "Use targets[target].contexts as the source of truth for context availability."
66
68
  - "Read linked context_resources, action_resources, and custom_context_resources before reasoning about fields, mutations, or custom data."
67
69
  - "Do not infer context field shape from the target id, page name, or widget placement."
package/docs/targets.md CHANGED
@@ -24,6 +24,19 @@
24
24
  `target` не является данными заказа, клиента или пользователя. Это только место встраивания.
25
25
  Данные нужно брать из контекстов, которые привязаны к этому `target`.
26
26
 
27
+ ## Оформление виджета в target
28
+
29
+ Виджет должен добавлять в target простой и предсказуемый inline UI: обычно `UiToolbarButton`,
30
+ `UiToolbarLink`, короткий текст или компактное действие с иконкой. Это сохраняет страницу CRM
31
+ стабильной и не раздувает место встраивания.
32
+
33
+ Если сценарий требует сложной формы, таблицы, карты, фильтров, summary-блоков или многошагового UI,
34
+ оставьте в target только компактный вход в сценарий, а основную логику перенесите в `UiModalSidebar`
35
+ или `UiModalWindow`.
36
+
37
+ Подробные правила композиции описаны в `@retailcrm/embed-ui-v1-components`
38
+ `docs/profiles/widgets/WidgetComposition.yml`.
39
+
27
40
  ## Проверка контекстов для `target`
28
41
 
29
42
  ```ts
@@ -132,5 +145,5 @@ const testTarget = defineTarget('customer/card:test.after', [
132
145
  - [`defineWidgetRunner`](./define-widget-runner.md) — как `target` попадает в компонент встраиваемого виджета.
133
146
  - [`menu-placements`](./menu-placements.md) — чем пункты меню для страниц отличаются от widget `target`.
134
147
  - [`page-routes`](./page-routes.md) — как описывать page `code` и CRM-маршрут.
135
- - [`CONCEPT`](../../v1-contexts/docs/ru/CONCEPT.md) — общий принцип работы контекстов.
136
- - [`CUSTOM`](../../v1-contexts/docs/ru/CUSTOM.md) — пользовательский контекст для custom fields.
148
+ - `@retailcrm/embed-ui-v1-contexts` `docs/ru/CONCEPT.md` — общий принцип работы контекстов.
149
+ - `@retailcrm/embed-ui-v1-contexts` `docs/ru/CUSTOM.md` — пользовательский контекст для custom fields.
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "embed-ui-v1-endpoint-mcp": "bin/embed-ui-v1-endpoint-mcp.mjs"
6
6
  },
7
7
  "type": "module",
8
- "version": "0.9.23",
8
+ "version": "0.9.25",
9
9
  "description": "Endpoint API for integrations in RetailCRM",
10
10
  "license": "MIT",
11
11
  "author": "RetailDriverLLC <integration@retailcrm.ru>",
@@ -85,7 +85,8 @@
85
85
  "bin",
86
86
  "dist",
87
87
  "docs",
88
- "README.md"
88
+ "README.md",
89
+ "templates"
89
90
  ],
90
91
  "scripts": {
91
92
  "build": "yarn build:docs && yarn build:code && yarn build:mcp && yarn build:meta",
@@ -100,17 +101,17 @@
100
101
  "peerDependencies": {
101
102
  "@omnicajs/vue-remote": "^0.2.24",
102
103
  "@remote-ui/rpc": "^1.4",
103
- "@retailcrm/embed-ui-v1-contexts": "^0.9.23",
104
- "@retailcrm/embed-ui-v1-types": "^0.9.23",
104
+ "@retailcrm/embed-ui-v1-contexts": "^0.9.25",
105
+ "@retailcrm/embed-ui-v1-types": "^0.9.25",
105
106
  "pinia": "^2.2",
106
107
  "vue": "^3.5"
107
108
  },
108
109
  "dependencies": {
109
110
  "@modelcontextprotocol/sdk": "^1.29.0",
110
111
  "@remote-ui/rpc": "^1.4.7",
111
- "@retailcrm/embed-ui-v1-components": "^0.9.23",
112
- "@retailcrm/embed-ui-v1-contexts": "^0.9.23",
113
- "@retailcrm/embed-ui-v1-types": "^0.9.23"
112
+ "@retailcrm/embed-ui-v1-components": "^0.9.25",
113
+ "@retailcrm/embed-ui-v1-contexts": "^0.9.25",
114
+ "@retailcrm/embed-ui-v1-types": "^0.9.25"
114
115
  },
115
116
  "devDependencies": {
116
117
  "@retailcrm/image-preview": "^1.0.2",
@@ -0,0 +1,45 @@
1
+ ---
2
+ name: embed-ui-v1-endpoint-runtime
3
+ description: Use when building, editing, or reviewing RetailCRM JS module endpoint wiring with @retailcrm/embed-ui-v1-endpoint. Covers pages, widgets, runners, targets, menu hierarchy, page publishing payloads, and public Host API boundaries.
4
+ ---
5
+
6
+ # Embed UI v1 Endpoint Runtime
7
+
8
+ Use this skill before changing JS module endpoint wiring, page registration, widget targets, or Host API navigation.
9
+
10
+ ## Reading order
11
+
12
+ 1. Read project `AGENTS.md` if it exists.
13
+ 2. Read `./node_modules/@retailcrm/embed-ui-v1-endpoint/README.md`.
14
+ 3. Read `./node_modules/@retailcrm/embed-ui-v1-endpoint/docs/README.md`.
15
+ 4. Read the relevant endpoint docs:
16
+ - `docs/define-runner.md`
17
+ - `docs/define-page-runner.md`
18
+ - `docs/define-widget-runner.md`
19
+ - `docs/page-routes.md`
20
+ - `docs/menu-placements.md`
21
+ - `docs/targets.md`
22
+ 5. If MCP resources are available, read `embed-ui-v1-endpoint://targets` and then the target profile for the target being changed.
23
+ 6. If MCP is not available, use `./node_modules/@retailcrm/embed-ui-v1-endpoint/docs/targets/*.yml` as fallback.
24
+
25
+ ## Workflow
26
+
27
+ 1. Identify whether the task is a page, widget, or shared endpoint runner change.
28
+ 2. For pages, keep the runtime runner map and extension config page descriptors aligned by page `code`.
29
+ 3. For widgets, choose the exact target from endpoint docs or MCP resources before writing UI.
30
+ 4. Use documented public entrypoints such as `@retailcrm/embed-ui-v1-endpoint/remote`; do not import from `dist/*`, source files, or repository-only paths.
31
+ 5. Keep widget inline UI compact; use component package widget composition guidance for UI mounted into CRM targets.
32
+
33
+ ## Page and menu checks
34
+
35
+ - Published page descriptors must be objects, not string page codes.
36
+ - Page descriptors need `code`, `menu`, and usually `menuItemTitle`.
37
+ - Use `parentMenuItemCode` and `menuItemOrdering` to model the intended CRM page/menu hierarchy.
38
+ - Breadcrumb-like navigation is derived by CRM from the page/menu hierarchy passed in the extension config; do not hand-roll breadcrumbs in the page unless the product task explicitly asks for local in-page navigation.
39
+ - For updating an already installed module, use the existing integration module edit/update flow and put pages under `integrationModule.integrations.embedJs.pages`.
40
+
41
+ ## Host API checks
42
+
43
+ - Use public Host API for location, query state, and navigation.
44
+ - Do not depend on internal endpoint runtime stores or private channel state.
45
+ - Keep route names, page codes, and extension descriptor values documented in the project.