@retailcrm/embed-ui-v1-endpoint 0.9.24 → 0.9.26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -0
- package/bin/embed-ui-v1-endpoint.mjs +43 -0
- package/docs/define-page-runner.md +16 -0
- package/docs/layout.md +6 -0
- package/docs/menu-placements.md +47 -0
- package/docs/page-routes.md +8 -0
- package/package.json +8 -7
- package/templates/skills/embed-ui-v1-endpoint-runtime/SKILL.md.txt +48 -0
package/README.md
CHANGED
|
@@ -85,6 +85,15 @@ npx @retailcrm/embed-ui-v1-endpoint init-agents
|
|
|
85
85
|
такого блока там ещё нет. С `--force` можно обновить уже существующий блок
|
|
86
86
|
пакета.
|
|
87
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
|
+
|
|
88
97
|
## Инициализация MCP-конфига
|
|
89
98
|
|
|
90
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,
|
|
@@ -457,6 +466,35 @@ const initAgents = (target, force) => {
|
|
|
457
466
|
console.log(`The ${PACKAGE_NAME} instructions were appended to the end of the file.`)
|
|
458
467
|
}
|
|
459
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
|
+
|
|
460
498
|
const writeMcpServerConfig = (target, relativePath, rootField, options, serverConfig) => {
|
|
461
499
|
const filePath = path.join(target, relativePath)
|
|
462
500
|
const fileExists = fs.existsSync(filePath)
|
|
@@ -573,6 +611,11 @@ const main = () => {
|
|
|
573
611
|
return
|
|
574
612
|
}
|
|
575
613
|
|
|
614
|
+
if (options.command === 'init-skills') {
|
|
615
|
+
initSkills(options.target, options)
|
|
616
|
+
return
|
|
617
|
+
}
|
|
618
|
+
|
|
576
619
|
throw new Error(`Unknown command: ${options.command}`)
|
|
577
620
|
} catch (error) {
|
|
578
621
|
console.error(error instanceof Error ? error.message : String(error))
|
|
@@ -45,6 +45,22 @@ const pageRunner = definePageRunner({
|
|
|
45
45
|
|
|
46
46
|
Если для `code` нет раннера, будет warning в консоль и noop-destroy.
|
|
47
47
|
|
|
48
|
+
## Runtime-проверка страницы
|
|
49
|
+
|
|
50
|
+
После первого минимального vertical slice проверяйте страницу внутри CRM host, а не только через build/lint.
|
|
51
|
+
|
|
52
|
+
Минимальный чек:
|
|
53
|
+
|
|
54
|
+
- manifest или publish payload содержит page descriptor object с `code`, `menu`, `menuItemTitle` и нужной
|
|
55
|
+
hierarchy metadata;
|
|
56
|
+
- `code` в `pages[]` совпадает с ключом runner map в `definePageRunner`;
|
|
57
|
+
- локальный dev server отдает `entrypoint` и `stylesheet` URL, которые указаны в extension config;
|
|
58
|
+
- пункт меню появился в CRM и открывает route `/modules/<module-code>/<page-code>`;
|
|
59
|
+
- frontend реально смонтировался в CRM host.
|
|
60
|
+
|
|
61
|
+
Если ошибка видна только в minified bundle, соберите или отдайте dev bundle без минификации до изменения кода
|
|
62
|
+
по догадке.
|
|
63
|
+
|
|
48
64
|
## `beforeMount`
|
|
49
65
|
|
|
50
66
|
`beforeMount` вызывается после `app.use(pinia)` и до `app.mount(...)`.
|
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
|
### Заголовок страницы
|
|
@@ -65,6 +67,7 @@
|
|
|
65
67
|
|
|
66
68
|
- Основной контент страницы обычно расположен на белых подложках.
|
|
67
69
|
- Подложка должна собирать один смысловой блок, а не случайный набор элементов.
|
|
70
|
+
- Padding `24px 32px 32px` ставится на саму подложку с контентом, а не на общий wrapper страницы.
|
|
68
71
|
- Если на экране есть несколько независимых смысловых секций, предпочтительнее использовать несколько подложек, чем одну перегруженную.
|
|
69
72
|
|
|
70
73
|
## 1. Страница со списком сущностей
|
|
@@ -103,6 +106,8 @@
|
|
|
103
106
|
|
|
104
107
|
- Таблица является главным содержимым списка.
|
|
105
108
|
- Она может листаться, пагинироваться и поддерживать выгрузку.
|
|
109
|
+
- `UiTable` не нужно заворачивать в дополнительную белую подложку: таблица сама задаёт табличную поверхность, границы и внутренние отступы.
|
|
110
|
+
- Wrapper вокруг таблицы допустим только как layout/scroll/width container без собственной белой карточки и без padding подложки.
|
|
106
111
|
- Не следует смешивать в одном списочном экране слишком много “карточной” логики; список должен оставаться в первую очередь инструментом поиска и просмотра.
|
|
107
112
|
|
|
108
113
|
Типичная компонентная основа:
|
|
@@ -337,6 +342,7 @@
|
|
|
337
342
|
4. Нужна ли общая панель сохранения, или каждый блок должен сохраняться отдельно?
|
|
338
343
|
5. Есть ли на странице не больше одного page-level `primary`-действия каждого варианта, а дополнительные `Default Primary` находятся только внутри отдельных `UiCollapseBox`?
|
|
339
344
|
6. Держатся ли отступы и расстояния сетки `4px`?
|
|
345
|
+
7. Не продублирован ли padding контентной подложки на корневом wrapper страницы?
|
|
340
346
|
|
|
341
347
|
---
|
|
342
348
|
|
package/docs/menu-placements.md
CHANGED
|
@@ -61,6 +61,48 @@
|
|
|
61
61
|
`menu: "private_main_menu"` и `parentMenuItemCode: "settings"`. Для страниц в разделе продаж используйте
|
|
62
62
|
`menu: "activity_main_menu"` и соответствующий parent menu item, например `orders`.
|
|
63
63
|
|
|
64
|
+
CRM также использует hierarchy из `pages[]` для видимой навигации и breadcrumb-like поведения. Сначала
|
|
65
|
+
моделируйте нужную иерархию через `menu`, `parentMenuItemCode` и `menuItemOrdering`; локальные ссылки внутри
|
|
66
|
+
страницы добавляйте только для дополнительной in-page navigation.
|
|
67
|
+
|
|
68
|
+
## Payload публикации
|
|
69
|
+
|
|
70
|
+
При обновлении уже установленного расширения синхронизируйте существующий integration module через
|
|
71
|
+
`/api/v5/integration-modules/{code}/edit`, а не создавайте новый инстанс регистрации. В payload страницы
|
|
72
|
+
должны находиться внутри `integrationModule.integrations.embedJs.pages`:
|
|
73
|
+
|
|
74
|
+
```json
|
|
75
|
+
{
|
|
76
|
+
"integrationModule": {
|
|
77
|
+
"clientId": "client-id-xxx",
|
|
78
|
+
"integrations": {
|
|
79
|
+
"embedJs": {
|
|
80
|
+
"entrypoint": "https://example.test/extension/demo/script",
|
|
81
|
+
"stylesheet": "https://example.test/extension/demo/stylesheet",
|
|
82
|
+
"runner": "demo",
|
|
83
|
+
"pages": [
|
|
84
|
+
{
|
|
85
|
+
"code": "orders-dashboard",
|
|
86
|
+
"menu": "activity_main_menu",
|
|
87
|
+
"parentMenuItemCode": "orders",
|
|
88
|
+
"menuItemOrdering": 100,
|
|
89
|
+
"menuItemTitle": {
|
|
90
|
+
"ru": "Заказы",
|
|
91
|
+
"en": "Orders",
|
|
92
|
+
"es": "Pedidos"
|
|
93
|
+
},
|
|
94
|
+
"pageHelpLink": null
|
|
95
|
+
}
|
|
96
|
+
]
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Если локальный API client не знает DTO для расширенного payload, используйте поддержанный custom/request
|
|
104
|
+
method с обычным JSON-объектом вместо добавления локального DTO, который serializer не умеет обрабатывать.
|
|
105
|
+
|
|
64
106
|
## Пример справочника меню
|
|
65
107
|
|
|
66
108
|
Конкретные `placement`, `item code` и `route` нужно брать из host/manifest расширения.
|
|
@@ -92,6 +134,11 @@ const pageRunner = definePageRunner({
|
|
|
92
134
|
Если host откроет страницу с `code`, которого нет в runner map, `definePageRunner` запишет warning
|
|
93
135
|
в консоль и не смонтирует страницу.
|
|
94
136
|
|
|
137
|
+
После изменения меню или pages manifest проверьте локальную CRM установку: пункт меню должен появиться,
|
|
138
|
+
route `/modules/<module-code>/<page-code>` должен открываться, а `entrypoint` и `stylesheet` из extension
|
|
139
|
+
config должны отдаваться локальным dev server. При runtime-ошибках в minified bundle сначала включите dev
|
|
140
|
+
bundle или sourcemaps.
|
|
141
|
+
|
|
95
142
|
Читайте также:
|
|
96
143
|
|
|
97
144
|
- [`page-routes`](./page-routes.md) — как описывать page `code` и CRM-маршрут.
|
package/docs/page-routes.md
CHANGED
|
@@ -12,6 +12,10 @@ page `code` нужно описывать объектом manifest `pages[]` с
|
|
|
12
12
|
строковую форму `pages: ["orders-dashboard"]` для публикации через RetailCRM API: backend ожидает
|
|
13
13
|
`ConfigurationPage` object, а страница без `menu` не откроется по route `/modules/<module-code>/<page-code>`.
|
|
14
14
|
|
|
15
|
+
Build/lint успех не доказывает, что страница откроется в CRM. После добавления новой страницы проверьте
|
|
16
|
+
runtime lifecycle в host: page descriptor, menu item, route `/modules/<module-code>/<page-code>`,
|
|
17
|
+
доступность `entrypoint` и `stylesheet`, и фактический mount frontend-кода.
|
|
18
|
+
|
|
15
19
|
## Что такое `page code`
|
|
16
20
|
|
|
17
21
|
`page code` — стабильный идентификатор встраиваемой страницы внутри расширения.
|
|
@@ -94,6 +98,10 @@ const openSettings = (host: HostApi) => {
|
|
|
94
98
|
}
|
|
95
99
|
```
|
|
96
100
|
|
|
101
|
+
Breadcrumb-like navigation для module pages строится CRM из hierarchy в `pages[]`: `menu`,
|
|
102
|
+
`parentMenuItemCode`, `menuItemOrdering` и связанных metadata. Не собирайте breadcrumbs вручную внутри
|
|
103
|
+
страницы, если продуктовая задача явно не просит локальную in-page navigation.
|
|
104
|
+
|
|
97
105
|
Читайте также:
|
|
98
106
|
|
|
99
107
|
- [`menu-placements`](./menu-placements.md) — как связать пункт меню, page `code` и маршрут.
|
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.
|
|
8
|
+
"version": "0.9.26",
|
|
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.
|
|
104
|
-
"@retailcrm/embed-ui-v1-types": "^0.9.
|
|
104
|
+
"@retailcrm/embed-ui-v1-contexts": "^0.9.26",
|
|
105
|
+
"@retailcrm/embed-ui-v1-types": "^0.9.26",
|
|
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.
|
|
112
|
-
"@retailcrm/embed-ui-v1-contexts": "^0.9.
|
|
113
|
-
"@retailcrm/embed-ui-v1-types": "^0.9.
|
|
112
|
+
"@retailcrm/embed-ui-v1-components": "^0.9.26",
|
|
113
|
+
"@retailcrm/embed-ui-v1-contexts": "^0.9.26",
|
|
114
|
+
"@retailcrm/embed-ui-v1-types": "^0.9.26"
|
|
114
115
|
},
|
|
115
116
|
"devDependencies": {
|
|
116
117
|
"@retailcrm/image-preview": "^1.0.2",
|
|
@@ -0,0 +1,48 @@
|
|
|
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
|
+
6. After the first page vertical slice, verify it in the CRM host: menu item, `/modules/<moduleCode>/<pageCode>` route, entrypoint URL, stylesheet URL, and actual frontend mount.
|
|
33
|
+
7. If a runtime error appears only in a minified bundle, switch to a dev bundle or sourcemaps before guessing.
|
|
34
|
+
|
|
35
|
+
## Page and menu checks
|
|
36
|
+
|
|
37
|
+
- Published page descriptors must be objects, not string page codes.
|
|
38
|
+
- Page descriptors need `code`, `menu`, and usually `menuItemTitle`.
|
|
39
|
+
- Use `parentMenuItemCode` and `menuItemOrdering` to model the intended CRM page/menu hierarchy.
|
|
40
|
+
- 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.
|
|
41
|
+
- For updating an already installed module, use the existing integration module edit/update flow and put pages under `integrationModule.integrations.embedJs.pages`.
|
|
42
|
+
- Build/lint success does not prove page rendering; check the installed module in the CRM host when page routing or menu placement changed.
|
|
43
|
+
|
|
44
|
+
## Host API checks
|
|
45
|
+
|
|
46
|
+
- Use public Host API for location, query state, and navigation.
|
|
47
|
+
- Do not depend on internal endpoint runtime stores or private channel state.
|
|
48
|
+
- Keep route names, page codes, and extension descriptor values documented in the project.
|