@retailcrm/embed-ui-v1-contexts 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
CHANGED
|
@@ -60,6 +60,16 @@ npx @retailcrm/embed-ui-v1-contexts init-agents
|
|
|
60
60
|
такого блока там ещё нет. С `--force` можно обновить уже существующий блок
|
|
61
61
|
пакета.
|
|
62
62
|
|
|
63
|
+
Для project-level skills можно создать `.agents/skills/embed-ui-v1-contexts-usage/SKILL.md`:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
npx @retailcrm/embed-ui-v1-contexts init-skills
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Skill описывает повторяемый workflow применения контекстов в коде: проверку доступности
|
|
70
|
+
контекста в target, выбор public import, readonly/writable семантику, actions и fallback
|
|
71
|
+
на generated YAML profiles, если MCP недоступен.
|
|
72
|
+
|
|
63
73
|
## Инициализация MCP-конфига
|
|
64
74
|
|
|
65
75
|
Пакет также может сам добавить 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'
|
|
@@ -12,6 +13,8 @@ const AGENTS_SECTION_END = '<!-- embed-ui-agents:@retailcrm/embed-ui-v1-contexts
|
|
|
12
13
|
const README_MCP_SECTION_HEADER = '## MCP For AI Assistants: @retailcrm/embed-ui-v1-contexts'
|
|
13
14
|
const README_MCP_MARKER = 'embed-ui-v1-contexts://contexts'
|
|
14
15
|
const MCP_SERVER_NAME = 'retailcrm-embed-ui-v1-contexts'
|
|
16
|
+
const SKILL_NAME = 'embed-ui-v1-contexts-usage'
|
|
17
|
+
const SKILL_TEMPLATE_PATH = `templates/skills/${SKILL_NAME}/SKILL.md.txt`
|
|
15
18
|
const MCP_BIN_NAME = process.platform === 'win32' ? 'embed-ui-v1-contexts-mcp.cmd' : 'embed-ui-v1-contexts-mcp'
|
|
16
19
|
const RELATIVE_MCP_BIN_PATH = `./node_modules/.bin/${MCP_BIN_NAME}`
|
|
17
20
|
const CLAUDE_PROJECT_MCP_BIN_PATH = `\${CLAUDE_PROJECT_DIR:-.}/node_modules/.bin/${MCP_BIN_NAME}`
|
|
@@ -48,6 +51,7 @@ const MCP_CLIENT_CONFIGS = {
|
|
|
48
51
|
const HELP_TEXT = `Usage:
|
|
49
52
|
npx ${PACKAGE_NAME} init-agents [target] [options]
|
|
50
53
|
npx ${PACKAGE_NAME} init-config [target] [options]
|
|
54
|
+
npx ${PACKAGE_NAME} init-skills [target] [options]
|
|
51
55
|
|
|
52
56
|
Options:
|
|
53
57
|
-f, --force Replace existing managed sections and MCP server entries
|
|
@@ -57,6 +61,7 @@ Options:
|
|
|
57
61
|
|
|
58
62
|
Examples:
|
|
59
63
|
npx ${PACKAGE_NAME} init-agents
|
|
64
|
+
npx ${PACKAGE_NAME} init-skills
|
|
60
65
|
npx ${PACKAGE_NAME} init-agents ./my-project
|
|
61
66
|
npx ${PACKAGE_NAME} init-agents --force
|
|
62
67
|
npx ${PACKAGE_NAME} init-config ./my-project
|
|
@@ -74,6 +79,10 @@ const printMcpNotice = (message) => {
|
|
|
74
79
|
console.log(`MCP: ${message}`)
|
|
75
80
|
}
|
|
76
81
|
|
|
82
|
+
const packageRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..')
|
|
83
|
+
|
|
84
|
+
const createSkill = () => fs.readFileSync(path.join(packageRoot, SKILL_TEMPLATE_PATH), 'utf8')
|
|
85
|
+
|
|
77
86
|
const parseArgs = (argv) => {
|
|
78
87
|
const options = {
|
|
79
88
|
command: null,
|
|
@@ -459,6 +468,35 @@ const initAgents = (target, force) => {
|
|
|
459
468
|
console.log(`The ${PACKAGE_NAME} instructions were appended to the end of the file.`)
|
|
460
469
|
}
|
|
461
470
|
|
|
471
|
+
const initSkills = (target, options) => {
|
|
472
|
+
if (!fs.existsSync(target)) {
|
|
473
|
+
throw new Error(`Target path does not exist: ${target}`)
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
const stat = fs.statSync(target)
|
|
477
|
+
|
|
478
|
+
if (!stat.isDirectory()) {
|
|
479
|
+
throw new Error(`Target path is not a directory: ${target}`)
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
const skillPath = path.join(target, '.agents', 'skills', SKILL_NAME, 'SKILL.md')
|
|
483
|
+
const fileExists = fs.existsSync(skillPath)
|
|
484
|
+
|
|
485
|
+
if (fileExists && !options.force) {
|
|
486
|
+
console.log(`${skillPath} already exists`)
|
|
487
|
+
console.log('Nothing was changed. Re-run with --force to refresh that skill.')
|
|
488
|
+
return
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
if (!options.dryRun) {
|
|
492
|
+
fs.mkdirSync(path.dirname(skillPath), { recursive: true })
|
|
493
|
+
fs.writeFileSync(skillPath, createSkill(), 'utf8')
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
const action = fileExists ? 'updated' : 'created'
|
|
497
|
+
console.log(`SKILL: ${options.dryRun ? `would ${action}` : action} ${skillPath}`)
|
|
498
|
+
}
|
|
499
|
+
|
|
462
500
|
const writeMcpServerConfig = (target, relativePath, rootField, options, serverConfig) => {
|
|
463
501
|
const filePath = path.join(target, relativePath)
|
|
464
502
|
const fileExists = fs.existsSync(filePath)
|
|
@@ -575,6 +613,11 @@ const main = () => {
|
|
|
575
613
|
return
|
|
576
614
|
}
|
|
577
615
|
|
|
616
|
+
if (options.command === 'init-skills') {
|
|
617
|
+
initSkills(options.target, options)
|
|
618
|
+
return
|
|
619
|
+
}
|
|
620
|
+
|
|
578
621
|
throw new Error(`Unknown command: ${options.command}`)
|
|
579
622
|
} catch (error) {
|
|
580
623
|
console.error(error instanceof Error ? error.message : String(error))
|
package/package.json
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
},
|
|
7
7
|
"description": "Reactive contexts for RetailCRM JS API",
|
|
8
8
|
"type": "module",
|
|
9
|
-
"version": "0.9.
|
|
9
|
+
"version": "0.9.26",
|
|
10
10
|
"license": "MIT",
|
|
11
11
|
"author": "RetailDriverLLC <integration@retailcrm.ru>",
|
|
12
12
|
"repository": {
|
|
@@ -104,7 +104,8 @@
|
|
|
104
104
|
"dist",
|
|
105
105
|
"docs",
|
|
106
106
|
"types",
|
|
107
|
-
"README.md"
|
|
107
|
+
"README.md",
|
|
108
|
+
"templates"
|
|
108
109
|
],
|
|
109
110
|
"scripts": {
|
|
110
111
|
"build": "yarn prepare && yarn build:docs && yarn build:code && yarn build:mcp && yarn build:meta",
|
|
@@ -123,11 +124,11 @@
|
|
|
123
124
|
"dependencies": {
|
|
124
125
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
125
126
|
"@omnicajs/symfony-router": "^1.0.0",
|
|
126
|
-
"@retailcrm/embed-ui-v1-types": "^0.9.
|
|
127
|
+
"@retailcrm/embed-ui-v1-types": "^0.9.26"
|
|
127
128
|
},
|
|
128
129
|
"devDependencies": {
|
|
129
130
|
"@remote-ui/rpc": "^1.4.7",
|
|
130
|
-
"@retailcrm/embed-ui-v1-testing": "^0.9.
|
|
131
|
+
"@retailcrm/embed-ui-v1-testing": "^0.9.26",
|
|
131
132
|
"tsx": "^4.21.0",
|
|
132
133
|
"typescript": "^5.9.3",
|
|
133
134
|
"vite": "^7.3.2",
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: embed-ui-v1-contexts-usage
|
|
3
|
+
description: Use when applying RetailCRM JS API contexts in extension code with @retailcrm/embed-ui-v1-contexts. Covers target-to-context selection, public imports, readonly versus writable fields, actions, custom contexts, dictionaries, and MCP/profile fallback.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Embed UI v1 Contexts Usage
|
|
7
|
+
|
|
8
|
+
Use this skill before changing code that reads CRM page data, writes context fields, calls context actions, or works with custom fields through `@retailcrm/embed-ui-v1-contexts`.
|
|
9
|
+
|
|
10
|
+
## Reading order
|
|
11
|
+
|
|
12
|
+
1. Read project `AGENTS.md` if it exists.
|
|
13
|
+
2. Read `./node_modules/@retailcrm/embed-ui-v1-contexts/README.md`.
|
|
14
|
+
3. Read `./node_modules/@retailcrm/embed-ui-v1-contexts/docs/ru/CONCEPT.md`.
|
|
15
|
+
4. Read `./node_modules/@retailcrm/embed-ui-v1-contexts/docs/ru/CUSTOM.md` if custom fields or custom dictionaries are involved.
|
|
16
|
+
5. If the task is tied to a widget target and endpoint MCP is available, read that target profile first; it is the source of truth for available `contexts`, `custom_contexts`, and `action_scopes`.
|
|
17
|
+
6. If contexts MCP resources are available, start from:
|
|
18
|
+
- `embed-ui-v1-contexts://contexts`
|
|
19
|
+
- `embed-ui-v1-contexts://actions`
|
|
20
|
+
- `embed-ui-v1-contexts://custom-contexts`
|
|
21
|
+
7. Then read the specific profile before coding:
|
|
22
|
+
- `embed-ui-v1-contexts://contexts/<encoded-context>`
|
|
23
|
+
- `embed-ui-v1-contexts://actions/<encoded-scope>`
|
|
24
|
+
- `embed-ui-v1-contexts://custom-contexts/<encoded-entity>`
|
|
25
|
+
8. If MCP is not available, use generated YAML profiles from `./node_modules/@retailcrm/embed-ui-v1-contexts/docs/contexts/*.yml`, `docs/actions/*.yml`, and `docs/custom-contexts/*.yml`.
|
|
26
|
+
|
|
27
|
+
## Workflow
|
|
28
|
+
|
|
29
|
+
1. Identify where the code runs: CRM page, widget target, page runner, or shared remote module.
|
|
30
|
+
2. Confirm that the needed context, custom context, or action scope is available there; do not infer availability from page names or target ids.
|
|
31
|
+
3. Pick the exact public entrypoint from the profile `public_import` or docs, such as `@retailcrm/embed-ui-v1-contexts/remote/order/card`.
|
|
32
|
+
4. Read context fields through `useContext()` and keep UI state derived from reactive store values instead of copying context data into parallel state.
|
|
33
|
+
5. For writes, check the field `readonly` flag and `mutation` notes. Assign only writable fields directly.
|
|
34
|
+
6. For readonly aggregates or business operations, use the documented `useActions()` method and payload shape instead of mutating nested data.
|
|
35
|
+
7. For custom contexts, call `initialize()` before relying on schema-backed fields, handle rejection, and use `useCustomField()` with the expected `kind`.
|
|
36
|
+
8. For custom dictionary fields, resolve the dictionary code from the schema and load options through `useDictionary()`.
|
|
37
|
+
|
|
38
|
+
## High-signal checks
|
|
39
|
+
|
|
40
|
+
- Do not assume all contexts are available on all targets.
|
|
41
|
+
- Do not import from `@retailcrm/embed-ui-v1-contexts/dist/*`, source files, or repository-only paths.
|
|
42
|
+
- Do not infer mutability from TypeScript shape alone; read the generated profile action and mutation notes.
|
|
43
|
+
- Use current item identifiers from the context, such as `OrderItem.index`, when action notes require them.
|
|
44
|
+
- Preserve host-mediated behavior: let CRM perform action validation, mutation, and synchronization.
|
|
45
|
+
- If a field description is vague or absent, state that any business meaning is an inference.
|
|
46
|
+
- Keep context usage aligned with endpoint target profiles when `@retailcrm/embed-ui-v1-endpoint` is also installed.
|