@retailcrm/embed-ui-v1-components 0.9.13 → 0.9.15
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/AGENTS.md +126 -0
- package/README.md +24 -0
- package/assets/stylesheets/palette.less +11 -6
- package/bin/embed-ui-v1-components.mjs +209 -0
- package/bin/postinstall.mjs +37 -0
- package/dist/host.cjs +1900 -590
- package/dist/host.css +659 -6
- package/dist/host.d.ts +2374 -50
- package/dist/host.js +1901 -591
- package/dist/remote.cjs +610 -33
- package/dist/remote.d.ts +729 -48
- package/dist/remote.js +612 -35
- package/docs/AI.md +106 -0
- package/docs/COMPONENTS.md +96 -0
- package/docs/FORMAT.md +248 -0
- package/docs/PROFILES.md +64 -0
- package/docs/README.md +65 -0
- package/docs/STYLING.md +156 -0
- package/docs/profiles/UiAddButton.yml +45 -0
- package/docs/profiles/UiAlert.yml +36 -0
- package/docs/profiles/UiAvatar.yml +36 -0
- package/docs/profiles/UiAvatarList.yml +30 -0
- package/docs/profiles/UiButton.yml +221 -0
- package/docs/profiles/UiCalendar.yml +36 -0
- package/docs/profiles/UiCheckbox.yml +41 -0
- package/docs/profiles/UiCollapse.yml +28 -0
- package/docs/profiles/UiCollapseBox.yml +39 -0
- package/docs/profiles/UiCollapseGroup.yml +27 -0
- package/docs/profiles/UiCopyButton.yml +40 -0
- package/docs/profiles/UiDate.yml +26 -0
- package/docs/profiles/UiDatePicker.yml +47 -0
- package/docs/profiles/UiError.yml +20 -0
- package/docs/profiles/UiField.yml +229 -0
- package/docs/profiles/UiImage.yml +27 -0
- package/docs/profiles/UiInfobox.yml +33 -0
- package/docs/profiles/UiLink.yml +39 -0
- package/docs/profiles/UiLoader.yml +26 -0
- package/docs/profiles/UiMenuItem.yml +45 -0
- package/docs/profiles/UiMenuItemGroup.yml +38 -0
- package/docs/profiles/UiModalSidebar.yml +34 -0
- package/docs/profiles/UiModalWindow.yml +32 -0
- package/docs/profiles/UiModalWindowSurface.yml +29 -0
- package/docs/profiles/UiNumberStepper.yml +40 -0
- package/docs/profiles/UiPageHeader.yml +240 -0
- package/docs/profiles/UiPopper.yml +197 -0
- package/docs/profiles/UiPopperConnector.yml +109 -0
- package/docs/profiles/UiPopperTarget.yml +112 -0
- package/docs/profiles/UiRadio.yml +26 -0
- package/docs/profiles/UiRadioSwitch.yml +224 -0
- package/docs/profiles/UiRadioSwitchOption.yml +113 -0
- package/docs/profiles/UiScrollBox.yml +19 -0
- package/docs/profiles/UiSelect.yml +318 -0
- package/docs/profiles/UiSelectOption.yml +32 -0
- package/docs/profiles/UiSelectOptionGroup.yml +26 -0
- package/docs/profiles/UiSlider.yml +26 -0
- package/docs/profiles/UiSwitch.yml +25 -0
- package/docs/profiles/UiTab.yml +114 -0
- package/docs/profiles/UiTabGroup.yml +233 -0
- package/docs/profiles/UiTable.yml +148 -0
- package/docs/profiles/UiTableBodyCell.yml +35 -0
- package/docs/profiles/UiTableColumn.yml +38 -0
- package/docs/profiles/UiTableFooterButton.yml +32 -0
- package/docs/profiles/UiTableFooterSection.yml +26 -0
- package/docs/profiles/UiTableHeadCell.yml +32 -0
- package/docs/profiles/UiTableSorter.yml +33 -0
- package/docs/profiles/UiTag.yml +29 -0
- package/docs/profiles/UiTextbox.yml +388 -0
- package/docs/profiles/UiTimePicker.yml +34 -0
- package/docs/profiles/UiToolbarButton.yml +25 -0
- package/docs/profiles/UiToolbarLink.yml +20 -0
- package/docs/profiles/UiTooltip.yml +31 -0
- package/docs/profiles/UiTransition.yml +15 -0
- package/docs/profiles/UiYandexMap.yml +17 -0
- package/package.json +11 -2
package/AGENTS.md
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
# AGENTS.md
|
|
2
|
+
|
|
3
|
+
## Purpose
|
|
4
|
+
|
|
5
|
+
This file is for AI assistants and automation that use the built package
|
|
6
|
+
`@retailcrm/embed-ui-v1-components` in application code.
|
|
7
|
+
|
|
8
|
+
It is not a contributor guide for editing the internal source of this workspace.
|
|
9
|
+
Treat this file as usage guidance for the published API.
|
|
10
|
+
|
|
11
|
+
## What This Package Is
|
|
12
|
+
|
|
13
|
+
- Package: `@retailcrm/embed-ui-v1-components`
|
|
14
|
+
- Role: UI component library for RetailCRM JS extensions
|
|
15
|
+
- Framework: Vue 3
|
|
16
|
+
- Main consumer entrypoint: `@retailcrm/embed-ui-v1-components/remote`
|
|
17
|
+
|
|
18
|
+
This package exposes declarative UI primitives that are rendered by RetailCRM host runtime.
|
|
19
|
+
|
|
20
|
+
## How To Import
|
|
21
|
+
|
|
22
|
+
- For extension UI code, import from `@retailcrm/embed-ui-v1-components/remote`.
|
|
23
|
+
- For icons and static assets, import from `@retailcrm/embed-ui-v1-components/assets/...`.
|
|
24
|
+
- Do not import from package-internal files such as `dist/*` or internal workspace files when writing extension code.
|
|
25
|
+
- Do not recommend `@retailcrm/embed-ui-v1-components/host` unless the task is explicitly about CRM host internals.
|
|
26
|
+
|
|
27
|
+
## Mental Model
|
|
28
|
+
|
|
29
|
+
- `remote` is the public API for extension authors.
|
|
30
|
+
- Components from `remote` do not represent a standalone design system outside RetailCRM.
|
|
31
|
+
- Extension code describes UI declaratively, and the CRM host side interprets and renders it.
|
|
32
|
+
- Because of this architecture, prefer documented public props and slots over assumptions based on internal implementation.
|
|
33
|
+
|
|
34
|
+
## Safe Default Recommendation
|
|
35
|
+
|
|
36
|
+
When building UI in an extension, start with imports like:
|
|
37
|
+
|
|
38
|
+
```ts
|
|
39
|
+
import {
|
|
40
|
+
UiButton,
|
|
41
|
+
UiField,
|
|
42
|
+
UiPageHeader,
|
|
43
|
+
UiSelect,
|
|
44
|
+
UiTextbox,
|
|
45
|
+
} from '@retailcrm/embed-ui-v1-components/remote'
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Public API Areas
|
|
49
|
+
|
|
50
|
+
Commonly used exports from `remote` include:
|
|
51
|
+
|
|
52
|
+
- form controls:
|
|
53
|
+
`UiTextbox`, `UiCheckbox`, `UiRadio`, `UiSwitch`, `UiSlider`, `UiNumberStepper`
|
|
54
|
+
- selection and date controls:
|
|
55
|
+
`UiSelect`, `UiSelectOption`, `UiSelectOptionGroup`, `UiDatePicker`, `UiTimePicker`, `UiCalendar`
|
|
56
|
+
- layout and structure:
|
|
57
|
+
`UiField`, `UiPageHeader`, `UiCollapse`, `UiCollapseBox`, `UiScrollBox`
|
|
58
|
+
- actions and links:
|
|
59
|
+
`UiButton`, `UiAddButton`, `UiCopyButton`, `UiToolbarButton`, `UiToolbarLink`, `UiLink`
|
|
60
|
+
- feedback and overlays:
|
|
61
|
+
`UiAlert`, `UiInfobox`, `UiError`, `UiLoader`, `UiTooltip`, `UiModalWindow`, `UiModalSidebar`
|
|
62
|
+
- content and data display:
|
|
63
|
+
`UiAvatar`, `UiAvatarList`, `UiDate`, `UiImage`, `UiTag`, `UiTable`, `UiTableColumn`, `UiYandexMap`
|
|
64
|
+
- helpers:
|
|
65
|
+
`usePreview`, `ImageWorkersKey`, `formatDate`, `formatDateTime`, `formatTime`
|
|
66
|
+
|
|
67
|
+
## Usage Rules
|
|
68
|
+
|
|
69
|
+
- Prefer package public exports over reimplementing CRM-styled controls manually.
|
|
70
|
+
- Match component choice to semantics:
|
|
71
|
+
use `UiField` for labeled form controls, `UiAlert` for state messages, `UiPageHeader` for page-level headings.
|
|
72
|
+
- Keep imports on the public package boundary.
|
|
73
|
+
- If you are unsure whether something is public, assume only exports from `remote` and `assets/*` are safe for consumer code.
|
|
74
|
+
- If a needed capability is missing from the public API, say that clearly instead of suggesting internal imports.
|
|
75
|
+
|
|
76
|
+
## What To Avoid
|
|
77
|
+
|
|
78
|
+
- Do not import from `@retailcrm/embed-ui-v1-components/host` in normal extension code.
|
|
79
|
+
- Do not rely on internal file paths from this repository.
|
|
80
|
+
- Do not treat Storybook examples or internal source layout as stable runtime API.
|
|
81
|
+
- Do not assume every host-side component is available to extension authors.
|
|
82
|
+
|
|
83
|
+
## Example
|
|
84
|
+
|
|
85
|
+
```vue
|
|
86
|
+
<template>
|
|
87
|
+
<UiPageHeader
|
|
88
|
+
title="История заказа"
|
|
89
|
+
description="Последние изменения и служебные действия"
|
|
90
|
+
/>
|
|
91
|
+
|
|
92
|
+
<UiField id="comment" label="Комментарий">
|
|
93
|
+
<UiTextbox v-model="comment" placeholder="Введите текст" />
|
|
94
|
+
</UiField>
|
|
95
|
+
|
|
96
|
+
<UiButton @click="save">
|
|
97
|
+
Сохранить
|
|
98
|
+
</UiButton>
|
|
99
|
+
</template>
|
|
100
|
+
|
|
101
|
+
<script lang="ts" setup>
|
|
102
|
+
import { ref } from 'vue'
|
|
103
|
+
|
|
104
|
+
import {
|
|
105
|
+
UiButton,
|
|
106
|
+
UiField,
|
|
107
|
+
UiPageHeader,
|
|
108
|
+
UiTextbox,
|
|
109
|
+
} from '@retailcrm/embed-ui-v1-components/remote'
|
|
110
|
+
|
|
111
|
+
const comment = ref('')
|
|
112
|
+
|
|
113
|
+
const save = () => {}
|
|
114
|
+
</script>
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## If You Need More Context
|
|
118
|
+
|
|
119
|
+
- Package README:
|
|
120
|
+
[`./README.md`](./README.md)
|
|
121
|
+
- Human-oriented package docs:
|
|
122
|
+
[`./docs/README.md`](./docs/README.md)
|
|
123
|
+
- Machine-oriented package summary:
|
|
124
|
+
[`./docs/AI.md`](./docs/AI.md)
|
|
125
|
+
- Component profiles:
|
|
126
|
+
[`./docs/PROFILES.md`](./docs/PROFILES.md)
|
package/README.md
CHANGED
|
@@ -41,3 +41,27 @@ import { UiButton } from '@retailcrm/embed-ui-v1-components/remote'
|
|
|
41
41
|
интерфейс. Библиотека также содержит `@retailcrm/embed-ui-v1-components/host` – набор компонентов,
|
|
42
42
|
который будет использовать CRM при интерпретации инструкций от расширений. **_Не используйте_** host компоненты
|
|
43
43
|
как часть кода расширения.
|
|
44
|
+
|
|
45
|
+
## Документация пакета
|
|
46
|
+
|
|
47
|
+
Дополнительные материалы по пакету находятся в `docs/`:
|
|
48
|
+
|
|
49
|
+
- [`docs/README.md`](./docs/README.md) — обзор пакета и правил использования.
|
|
50
|
+
- [`docs/COMPONENTS.md`](./docs/COMPONENTS.md) — карта публичных компонентов.
|
|
51
|
+
- [`docs/AI.md`](./docs/AI.md) — контекст для ИИ и автоматизаций.
|
|
52
|
+
- [`docs/PROFILES.md`](./docs/PROFILES.md) — AI-friendly YAML-профили компонентов.
|
|
53
|
+
- [`docs/FORMAT.md`](./docs/FORMAT.md) — формат описания компонента для AI-агентов.
|
|
54
|
+
|
|
55
|
+
## AI и инициализация `AGENTS.md`
|
|
56
|
+
|
|
57
|
+
После установки пакет показывает подсказку, что внутри есть AI-заметки и YAML-профили компонентов.
|
|
58
|
+
|
|
59
|
+
Если в целевом проекте еще нет `AGENTS.md`, можно сгенерировать стартовый файл командой:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
npx @retailcrm/embed-ui-v1-components init-agents
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Если `AGENTS.md` уже существует, команда допишет в конец инструкции для
|
|
66
|
+
`@retailcrm/embed-ui-v1-components`, если такого блока там еще нет. С `--force`
|
|
67
|
+
можно обновить уже существующий блок пакета.
|
|
@@ -11,7 +11,8 @@
|
|
|
11
11
|
@red-800: #932121;
|
|
12
12
|
@red-900: #932121;
|
|
13
13
|
|
|
14
|
-
@red-
|
|
14
|
+
@red-translucent: rgba(255, 83, 83, 0.1);
|
|
15
|
+
@red-transparent: @red-translucent;
|
|
15
16
|
|
|
16
17
|
/* Blue */
|
|
17
18
|
@blue-100: #EDF4FF;
|
|
@@ -24,7 +25,8 @@
|
|
|
24
25
|
@blue-800: #0033A2;
|
|
25
26
|
@blue-900: #00228C;
|
|
26
27
|
|
|
27
|
-
@blue-
|
|
28
|
+
@blue-translucent: rgba(0, 94, 235, 0.12);
|
|
29
|
+
@blue-transparent: @blue-translucent;
|
|
28
30
|
|
|
29
31
|
/* Yellow */
|
|
30
32
|
@yellow-100: #FFF9F0;
|
|
@@ -37,7 +39,8 @@
|
|
|
37
39
|
@yellow-800: #BC6B01;
|
|
38
40
|
@yellow-900: #965601;
|
|
39
41
|
|
|
40
|
-
@yellow-
|
|
42
|
+
@yellow-translucent: rgba(254, 165, 48, 0.12);
|
|
43
|
+
@yellow-transparent: @yellow-translucent;
|
|
41
44
|
|
|
42
45
|
/* Green */
|
|
43
46
|
@green-100: #D8F8EE;
|
|
@@ -50,7 +53,8 @@
|
|
|
50
53
|
@green-800: #168561;
|
|
51
54
|
@green-900: #106349;
|
|
52
55
|
|
|
53
|
-
@green-
|
|
56
|
+
@green-translucent: rgba(34, 201, 147, 0.16);
|
|
57
|
+
@green-transparent: @green-translucent;
|
|
54
58
|
|
|
55
59
|
/* Purple */
|
|
56
60
|
@purple-100: #E5DBF8;
|
|
@@ -63,7 +67,8 @@
|
|
|
63
67
|
@purple-800: #371F7C;
|
|
64
68
|
@purple-900: #2D1A68;
|
|
65
69
|
|
|
66
|
-
@purple-
|
|
70
|
+
@purple-translucent: rgba(101, 40, 215, 0.12);
|
|
71
|
+
@purple-transparent: @purple-translucent;
|
|
67
72
|
|
|
68
73
|
/* Black */
|
|
69
74
|
@black-100: #323976;
|
|
@@ -85,4 +90,4 @@
|
|
|
85
90
|
@grey-600: #C7CDD4;
|
|
86
91
|
@grey-700: #AFB9C3;
|
|
87
92
|
@grey-800: #8A96A6;
|
|
88
|
-
@grey-900: #636F7F;
|
|
93
|
+
@grey-900: #636F7F;
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import fs from 'node:fs'
|
|
4
|
+
import path from 'node:path'
|
|
5
|
+
import process from 'node:process'
|
|
6
|
+
|
|
7
|
+
const PACKAGE_NAME = '@retailcrm/embed-ui-v1-components'
|
|
8
|
+
const DEFAULT_NEWLINE = '\n'
|
|
9
|
+
const AGENTS_SECTION_HEADER = '## @retailcrm/embed-ui-v1-components'
|
|
10
|
+
|
|
11
|
+
const HELP_TEXT = `Usage:
|
|
12
|
+
npx ${PACKAGE_NAME} init-agents [target] [options]
|
|
13
|
+
|
|
14
|
+
Options:
|
|
15
|
+
-f, --force Replace existing package section in AGENTS.md
|
|
16
|
+
-h, --help Show this help
|
|
17
|
+
|
|
18
|
+
Examples:
|
|
19
|
+
npx ${PACKAGE_NAME} init-agents
|
|
20
|
+
npx ${PACKAGE_NAME} init-agents ./my-project
|
|
21
|
+
npx ${PACKAGE_NAME} init-agents --force
|
|
22
|
+
`
|
|
23
|
+
|
|
24
|
+
const parseArgs = (argv) => {
|
|
25
|
+
const options = {
|
|
26
|
+
command: null,
|
|
27
|
+
target: process.cwd(),
|
|
28
|
+
force: false,
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const positionals = []
|
|
32
|
+
|
|
33
|
+
for (let index = 0; index < argv.length; index++) {
|
|
34
|
+
const argument = argv[index]
|
|
35
|
+
|
|
36
|
+
if (argument === '-h' || argument === '--help') {
|
|
37
|
+
console.log(HELP_TEXT)
|
|
38
|
+
process.exit(0)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (argument === '-f' || argument === '--force') {
|
|
42
|
+
options.force = true
|
|
43
|
+
continue
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (argument.startsWith('-')) {
|
|
47
|
+
throw new Error(`Unknown option: ${argument}`)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
positionals.push(argument)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (!positionals.length) {
|
|
54
|
+
throw new Error('Command is required')
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
options.command = positionals[0]
|
|
58
|
+
|
|
59
|
+
if (positionals.length >= 2) {
|
|
60
|
+
options.target = path.resolve(process.cwd(), positionals[1])
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (positionals.length > 2) {
|
|
64
|
+
throw new Error('Too many positional arguments')
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return options
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const createAgentsTemplate = () => {
|
|
71
|
+
return `# AGENTS.md
|
|
72
|
+
|
|
73
|
+
${AGENTS_SECTION_HEADER}
|
|
74
|
+
|
|
75
|
+
When working with \`${PACKAGE_NAME}\` in this project:
|
|
76
|
+
|
|
77
|
+
1. Read \`./node_modules/${PACKAGE_NAME}/docs/AI.md\`.
|
|
78
|
+
2. Then read \`./node_modules/${PACKAGE_NAME}/docs/COMPONENTS.md\`.
|
|
79
|
+
3. Then open the relevant profile from \`./node_modules/${PACKAGE_NAME}/docs/profiles/<Component>.yml\`.
|
|
80
|
+
4. Prefer those docs and profiles over guessing from internal implementation files.
|
|
81
|
+
5. Import only from documented public entrypoints:
|
|
82
|
+
- \`${PACKAGE_NAME}/remote\`
|
|
83
|
+
- \`${PACKAGE_NAME}/host\`
|
|
84
|
+
- \`${PACKAGE_NAME}/assets/...\`
|
|
85
|
+
6. Prefer \`${PACKAGE_NAME}/remote\` for extension UI code.
|
|
86
|
+
7. Do not import from package-internal files such as \`dist/*\`, repository-only paths, or source internals.
|
|
87
|
+
|
|
88
|
+
## Suggested Reading Order
|
|
89
|
+
|
|
90
|
+
1. \`docs/AI.md\`
|
|
91
|
+
2. \`docs/COMPONENTS.md\`
|
|
92
|
+
3. The relevant profile from \`docs/profiles/*.yml\`
|
|
93
|
+
4. \`docs/FORMAT.md\` if you need to understand profile structure
|
|
94
|
+
5. Storybook and public types only when no profile exists yet
|
|
95
|
+
` + DEFAULT_NEWLINE
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const createAgentsSection = () => {
|
|
99
|
+
return `${AGENTS_SECTION_HEADER}
|
|
100
|
+
|
|
101
|
+
When working with \`${PACKAGE_NAME}\` in this project:
|
|
102
|
+
|
|
103
|
+
1. Read \`./node_modules/${PACKAGE_NAME}/docs/AI.md\`.
|
|
104
|
+
2. Then read \`./node_modules/${PACKAGE_NAME}/docs/COMPONENTS.md\`.
|
|
105
|
+
3. Then open the relevant profile from \`./node_modules/${PACKAGE_NAME}/docs/profiles/<Component>.yml\`.
|
|
106
|
+
4. Prefer those docs and profiles over guessing from internal implementation files.
|
|
107
|
+
5. Import only from documented public entrypoints:
|
|
108
|
+
- \`${PACKAGE_NAME}/remote\`
|
|
109
|
+
- \`${PACKAGE_NAME}/host\`
|
|
110
|
+
- \`${PACKAGE_NAME}/assets/...\`
|
|
111
|
+
6. Prefer \`${PACKAGE_NAME}/remote\` for extension UI code.
|
|
112
|
+
7. Do not import from package-internal files such as \`dist/*\`, repository-only paths, or source internals.
|
|
113
|
+
|
|
114
|
+
## Suggested Reading Order
|
|
115
|
+
|
|
116
|
+
1. \`docs/AI.md\`
|
|
117
|
+
2. \`docs/COMPONENTS.md\`
|
|
118
|
+
3. The relevant profile from \`docs/profiles/*.yml\`
|
|
119
|
+
4. \`docs/FORMAT.md\` if you need to understand profile structure
|
|
120
|
+
5. Storybook and public types only when no profile exists yet
|
|
121
|
+
`
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const hasPackageSection = (content) => content.includes(AGENTS_SECTION_HEADER)
|
|
125
|
+
|
|
126
|
+
const appendSection = (content, section) => {
|
|
127
|
+
const trimmed = content.replace(/\s+$/u, '')
|
|
128
|
+
|
|
129
|
+
if (!trimmed.length) {
|
|
130
|
+
return `${section}${DEFAULT_NEWLINE}`
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
return `${trimmed}${DEFAULT_NEWLINE}${DEFAULT_NEWLINE}${section}${DEFAULT_NEWLINE}`
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const replaceSection = (content, section) => {
|
|
137
|
+
const escapedHeader = AGENTS_SECTION_HEADER.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
|
|
138
|
+
const sectionPattern = new RegExp(`${escapedHeader}[\\s\\S]*?(?=\\n##\\s|$)`, 'u')
|
|
139
|
+
|
|
140
|
+
if (!sectionPattern.test(content)) {
|
|
141
|
+
return appendSection(content, section)
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
return content
|
|
145
|
+
.replace(sectionPattern, section.trimEnd())
|
|
146
|
+
.replace(/\s+$/u, '') + DEFAULT_NEWLINE
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const initAgents = (target, force) => {
|
|
150
|
+
if (!fs.existsSync(target)) {
|
|
151
|
+
throw new Error(`Target path does not exist: ${target}`)
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const stat = fs.statSync(target)
|
|
155
|
+
|
|
156
|
+
if (!stat.isDirectory()) {
|
|
157
|
+
throw new Error(`Target path is not a directory: ${target}`)
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const agentsPath = path.join(target, 'AGENTS.md')
|
|
161
|
+
const section = createAgentsSection()
|
|
162
|
+
|
|
163
|
+
if (!fs.existsSync(agentsPath)) {
|
|
164
|
+
fs.writeFileSync(agentsPath, createAgentsTemplate(), 'utf8')
|
|
165
|
+
|
|
166
|
+
console.log(`AGENTS.md was created at ${agentsPath}`)
|
|
167
|
+
console.log('Next step: review it and adjust project-specific rules if needed.')
|
|
168
|
+
return
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
const currentContent = fs.readFileSync(agentsPath, 'utf8')
|
|
172
|
+
|
|
173
|
+
if (force) {
|
|
174
|
+
fs.writeFileSync(agentsPath, replaceSection(currentContent, section), 'utf8')
|
|
175
|
+
console.log(`AGENTS.md was updated at ${agentsPath}`)
|
|
176
|
+
console.log(`The ${PACKAGE_NAME} section was refreshed.`)
|
|
177
|
+
return
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
if (hasPackageSection(currentContent)) {
|
|
181
|
+
console.log(`AGENTS.md already contains a ${PACKAGE_NAME} section at ${agentsPath}`)
|
|
182
|
+
console.log('Nothing was changed. Re-run with --force to refresh that section.')
|
|
183
|
+
return
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
fs.writeFileSync(agentsPath, appendSection(currentContent, section), 'utf8')
|
|
187
|
+
|
|
188
|
+
console.log(`AGENTS.md was updated at ${agentsPath}`)
|
|
189
|
+
console.log(`The ${PACKAGE_NAME} instructions were appended to the end of the file.`)
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
const main = () => {
|
|
193
|
+
try {
|
|
194
|
+
const options = parseArgs(process.argv.slice(2))
|
|
195
|
+
|
|
196
|
+
if (options.command !== 'init-agents') {
|
|
197
|
+
throw new Error(`Unknown command: ${options.command}`)
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
initAgents(options.target, options.force)
|
|
201
|
+
} catch (error) {
|
|
202
|
+
console.error(error instanceof Error ? error.message : String(error))
|
|
203
|
+
console.error('')
|
|
204
|
+
console.error(HELP_TEXT)
|
|
205
|
+
process.exit(1)
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
main()
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { fileURLToPath } from 'node:url'
|
|
4
|
+
import fs from 'node:fs'
|
|
5
|
+
import path from 'node:path'
|
|
6
|
+
import process from 'node:process'
|
|
7
|
+
|
|
8
|
+
const PACKAGE_NAME = '@retailcrm/embed-ui-v1-components'
|
|
9
|
+
|
|
10
|
+
const currentFile = fileURLToPath(import.meta.url)
|
|
11
|
+
const packageRoot = path.resolve(path.dirname(currentFile), '..')
|
|
12
|
+
|
|
13
|
+
const isInstalledFromNodeModules = packageRoot.includes(`${path.sep}node_modules${path.sep}`)
|
|
14
|
+
|
|
15
|
+
if (!isInstalledFromNodeModules) {
|
|
16
|
+
process.exit(0)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const targetRoot = process.env.INIT_CWD
|
|
20
|
+
|
|
21
|
+
if (!targetRoot) {
|
|
22
|
+
process.exit(0)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const agentsPath = path.join(targetRoot, 'AGENTS.md')
|
|
26
|
+
const hasAgentsFile = fs.existsSync(agentsPath)
|
|
27
|
+
|
|
28
|
+
console.log('')
|
|
29
|
+
console.log(`[${PACKAGE_NAME}] AI docs are available in node_modules/${PACKAGE_NAME}/docs`)
|
|
30
|
+
console.log(`[${PACKAGE_NAME}] Start with docs/AI.md, docs/COMPONENTS.md, and docs/profiles/*.yml`)
|
|
31
|
+
|
|
32
|
+
if (!hasAgentsFile) {
|
|
33
|
+
console.log(`[${PACKAGE_NAME}] To scaffold AGENTS.md for this project, run:`)
|
|
34
|
+
console.log(` npx ${PACKAGE_NAME} init-agents`)
|
|
35
|
+
} else {
|
|
36
|
+
console.log(`[${PACKAGE_NAME}] AGENTS.md already exists in this project, so no scaffold was created automatically`)
|
|
37
|
+
}
|