@retailcrm/embed-ui-v1-components 0.9.21 → 0.9.22-alpha.1

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 (96) hide show
  1. package/AGENTS.md +3 -3
  2. package/README.md +3 -4
  3. package/assets/sprites/actions/add-square-outlined.svg +8 -0
  4. package/assets/sprites/actions/drag.svg +8 -0
  5. package/bin/embed-ui-v1-components.mjs +227 -50
  6. package/bin/postinstall.mjs +2 -1
  7. package/dist/host.cjs +1204 -488
  8. package/dist/host.css +629 -0
  9. package/dist/host.d.ts +100 -20
  10. package/dist/host.js +1205 -489
  11. package/dist/remote.cjs +1210 -153
  12. package/dist/remote.d.ts +786 -36
  13. package/dist/remote.js +1212 -155
  14. package/docs/AI.md +19 -20
  15. package/docs/COMPONENTS.md +58 -59
  16. package/docs/FORMAT.md +6 -8
  17. package/docs/PROFILES.md +34 -21
  18. package/docs/README.md +3 -6
  19. package/docs/profiles/{UiAddButton.yml → components/UiAddButton.yml} +49 -2
  20. package/docs/profiles/{UiAlert.yml → components/UiAlert.yml} +32 -2
  21. package/docs/profiles/{UiAvatar.yml → components/UiAvatar.yml} +17 -3
  22. package/docs/profiles/{UiAvatarList.yml → components/UiAvatarList.yml} +0 -2
  23. package/docs/profiles/{UiButton.yml → components/UiButton.yml} +14 -1
  24. package/docs/profiles/components/UiCalendar.yml +190 -0
  25. package/docs/profiles/{UiCheckbox.yml → components/UiCheckbox.yml} +28 -2
  26. package/docs/profiles/{UiCollapse.yml → components/UiCollapse.yml} +57 -2
  27. package/docs/profiles/{UiCollapseBox.yml → components/UiCollapseBox.yml} +64 -2
  28. package/docs/profiles/{UiCollapseGroup.yml → components/UiCollapseGroup.yml} +0 -2
  29. package/docs/profiles/{UiCopyButton.yml → components/UiCopyButton.yml} +19 -2
  30. package/docs/profiles/{UiDate.yml → components/UiDate.yml} +20 -2
  31. package/docs/profiles/{UiDatePicker.yml → components/UiDatePicker.yml} +51 -2
  32. package/docs/profiles/{UiError.yml → components/UiError.yml} +48 -2
  33. package/docs/profiles/{UiField.yml → components/UiField.yml} +46 -1
  34. package/docs/profiles/{UiInfobox.yml → components/UiInfobox.yml} +54 -2
  35. package/docs/profiles/{UiLink.yml → components/UiLink.yml} +22 -2
  36. package/docs/profiles/{UiLoader.yml → components/UiLoader.yml} +0 -2
  37. package/docs/profiles/{UiMenuItem.yml → components/UiMenuItem.yml} +0 -2
  38. package/docs/profiles/{UiMenuItemGroup.yml → components/UiMenuItemGroup.yml} +0 -2
  39. package/docs/profiles/{UiModalSidebar.yml → components/UiModalSidebar.yml} +80 -2
  40. package/docs/profiles/components/UiModalWindow.yml +181 -0
  41. package/docs/profiles/{UiModalWindowSurface.yml → components/UiModalWindowSurface.yml} +0 -2
  42. package/docs/profiles/{UiNumberStepper.yml → components/UiNumberStepper.yml} +14 -2
  43. package/docs/profiles/{UiPageHeader.yml → components/UiPageHeader.yml} +39 -1
  44. package/docs/profiles/components/UiPopconfirm.yml +164 -0
  45. package/docs/profiles/{UiPopper.yml → components/UiPopper.yml} +66 -1
  46. package/docs/profiles/{UiPopperConnector.yml → components/UiPopperConnector.yml} +0 -2
  47. package/docs/profiles/{UiPopperTarget.yml → components/UiPopperTarget.yml} +0 -2
  48. package/docs/profiles/{UiRadio.yml → components/UiRadio.yml} +15 -2
  49. package/docs/profiles/{UiRadioSwitch.yml → components/UiRadioSwitch.yml} +55 -1
  50. package/docs/profiles/{UiRadioSwitchOption.yml → components/UiRadioSwitchOption.yml} +0 -2
  51. package/docs/profiles/{UiScrollBox.yml → components/UiScrollBox.yml} +45 -2
  52. package/docs/profiles/{UiSelect.yml → components/UiSelect.yml} +133 -1
  53. package/docs/profiles/{UiSelectOption.yml → components/UiSelectOption.yml} +0 -2
  54. package/docs/profiles/{UiSelectOptionGroup.yml → components/UiSelectOptionGroup.yml} +0 -2
  55. package/docs/profiles/{UiSkeleton.yml → components/UiSkeleton.yml} +11 -2
  56. package/docs/profiles/{UiSlider.yml → components/UiSlider.yml} +85 -2
  57. package/docs/profiles/{UiSwitch.yml → components/UiSwitch.yml} +50 -2
  58. package/docs/profiles/{UiTab.yml → components/UiTab.yml} +126 -2
  59. package/docs/profiles/{UiTabGroup.yml → components/UiTabGroup.yml} +0 -1
  60. package/docs/profiles/components/UiTable.yml +622 -0
  61. package/docs/profiles/{UiTableBodyCell.yml → components/UiTableBodyCell.yml} +0 -2
  62. package/docs/profiles/{UiTableColumn.yml → components/UiTableColumn.yml} +0 -2
  63. package/docs/profiles/{UiTableFooterButton.yml → components/UiTableFooterButton.yml} +0 -2
  64. package/docs/profiles/{UiTableFooterSection.yml → components/UiTableFooterSection.yml} +0 -2
  65. package/docs/profiles/{UiTableHeadCell.yml → components/UiTableHeadCell.yml} +0 -2
  66. package/docs/profiles/{UiTableSorter.yml → components/UiTableSorter.yml} +0 -2
  67. package/docs/profiles/{UiTag.yml → components/UiTag.yml} +13 -2
  68. package/docs/profiles/{UiTextbox.yml → components/UiTextbox.yml} +20 -1
  69. package/docs/profiles/{UiTimePicker.yml → components/UiTimePicker.yml} +60 -2
  70. package/docs/profiles/{UiToggleButton.yml → components/UiToggleButton.yml} +16 -1
  71. package/docs/profiles/{UiToggleGroup.yml → components/UiToggleGroup.yml} +25 -1
  72. package/docs/profiles/{UiToggleGroupOption.yml → components/UiToggleGroupOption.yml} +0 -2
  73. package/docs/profiles/{UiToolbarButton.yml → components/UiToolbarButton.yml} +15 -2
  74. package/docs/profiles/{UiToolbarLink.yml → components/UiToolbarLink.yml} +13 -2
  75. package/docs/profiles/{UiTooltip.yml → components/UiTooltip.yml} +18 -2
  76. package/docs/profiles/{UiTransition.yml → components/UiTransition.yml} +0 -2
  77. package/docs/profiles/{UiYandexMap.yml → components/UiYandexMap.yml} +24 -2
  78. package/docs/profiles/pages/CardSettingsPage.yml +58 -0
  79. package/docs/profiles/pages/CollapseBlockPage.yml +46 -0
  80. package/docs/profiles/pages/EntityListPage.yml +66 -0
  81. package/docs/profiles/pages/ModalSidebar.yml +158 -0
  82. package/docs/profiles/pages/ModalWindow.yml +55 -0
  83. package/docs/profiles/pages/MultiColumnPage.yml +27 -0
  84. package/docs/profiles/pages/PageComposition.yml +56 -0
  85. package/package.json +1 -1
  86. package/docs/AGENT-DESIGN-GUIDELINES.md +0 -463
  87. package/docs/assets/page-guidelines/card-settings-page.png +0 -0
  88. package/docs/assets/page-guidelines/collapse-block-page.png +0 -0
  89. package/docs/assets/page-guidelines/entity-list-page.png +0 -0
  90. package/docs/assets/page-guidelines/modal-sidebar.png +0 -0
  91. package/docs/assets/page-guidelines/modal-window.png +0 -0
  92. package/docs/assets/page-guidelines/multi-column-page.png +0 -0
  93. package/docs/profiles/UiCalendar.yml +0 -76
  94. package/docs/profiles/UiImage.yml +0 -67
  95. package/docs/profiles/UiModalWindow.yml +0 -86
  96. package/docs/profiles/UiTable.yml +0 -300
package/AGENTS.md CHANGED
@@ -77,7 +77,7 @@ Commonly used exports from `remote` include:
77
77
 
78
78
  - Do not import from `@retailcrm/embed-ui-v1-components/host` in normal extension code.
79
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.
80
+ - Do not treat examples or internal source layout as stable runtime API.
81
81
  - Do not assume every host-side component is available to extension authors.
82
82
 
83
83
  ## Example
@@ -123,12 +123,12 @@ const save = () => {}
123
123
  - Machine-oriented package summary:
124
124
  [`./docs/AI.md`](./docs/AI.md)
125
125
  - Page composition guidelines:
126
- [`./docs/AGENT-DESIGN-GUIDELINES.md`](./docs/AGENT-DESIGN-GUIDELINES.md)
126
+ [`./docs/profiles/pages`](./docs/profiles/pages)
127
127
  - Component profiles:
128
128
  [`./docs/PROFILES.md`](./docs/PROFILES.md)
129
129
 
130
130
  For table, catalog, registry, journal, or search-result screens, read [`./docs/AI.md`](./docs/AI.md)
131
- and [`./docs/AGENT-DESIGN-GUIDELINES.md`](./docs/AGENT-DESIGN-GUIDELINES.md), then check the
131
+ and [`./docs/profiles/pages/EntityListPage.yml`](./docs/profiles/pages/EntityListPage.yml), then check the
132
132
  `UiTable` and `UiLink` profiles before generating code. Put filters above the table, persist
133
133
  filters and pagination in GET query parameters when routing exists, and set `size="small"` on
134
134
  `UiLink` inside table cells by default.
package/README.md CHANGED
@@ -50,15 +50,14 @@ import { UiButton } from '@retailcrm/embed-ui-v1-components/remote'
50
50
  - [`docs/README.md`](./docs/README.md) — обзор пакета и правил использования.
51
51
  - [`docs/COMPONENTS.md`](./docs/COMPONENTS.md) — карта публичных компонентов.
52
52
  - [`docs/AI.md`](./docs/AI.md) — контекст для ИИ и автоматизаций.
53
- - [`docs/PROFILES.md`](./docs/PROFILES.md) — AI-friendly YAML-профили компонентов.
53
+ - [`docs/PROFILES.md`](./docs/PROFILES.md) — AI-friendly YAML-профили компонентов и страниц.
54
54
  - [`docs/FORMAT.md`](./docs/FORMAT.md) — формат описания компонента для AI-агентов.
55
- - [`docs/AGENT-DESIGN-GUIDELINES.md`](./docs/AGENT-DESIGN-GUIDELINES.md) — правила построения страниц,
56
- модалок, шторок, фильтров и таблиц.
55
+ - [`docs/profiles/pages`](./docs/profiles/pages) — YAML-профили страниц, модалок, шторок, фильтров и таблиц.
57
56
 
58
57
  ## AI и инициализация `AGENTS.md`
59
58
 
60
59
  После установки пакет показывает подсказку, что внутри есть `README.md`, `AGENTS.md`,
61
- AI-заметки и YAML-профили компонентов.
60
+ AI-заметки и YAML-профили компонентов и страниц.
62
61
 
63
62
  Если в целевом проекте еще нет `AGENTS.md`, можно сгенерировать стартовый файл командой:
64
63
 
@@ -0,0 +1,8 @@
1
+ <svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <path
3
+ fill-rule="evenodd"
4
+ clip-rule="evenodd"
5
+ fill="currentColor"
6
+ d="M19 3H5C3.89543 3 3 3.89543 3 5V19C3 20.1046 3.89543 21 5 21H19C20.1046 21 21 20.1046 21 19V5C21 3.89543 20.1046 3 19 3ZM19 19H5V5H19V19ZM11 13H8.5C8.22386 13 8 12.7761 8 12.5V11.5C8 11.2239 8.22386 11 8.5 11H11V8.5C11 8.22386 11.2239 8 11.5 8H12.5C12.7761 8 13 8.22386 13 8.5V11H15.5C15.7761 11 16 11.2239 16 11.5V12.5C16 12.7761 15.7761 13 15.5 13H13V15.5C13 15.7761 12.7761 16 12.5 16H11.5C11.2239 16 11 15.7761 11 15.5V13Z"
7
+ />
8
+ </svg>
@@ -0,0 +1,8 @@
1
+ <svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg" >
2
+ <path
3
+ d="M7.4987 6.66683C8.41917 6.66683 9.16536 5.92064 9.16536 5.00016C9.16536 4.07969 8.41917 3.3335 7.4987 3.3335C6.57822 3.3335 5.83203 4.07969 5.83203 5.00016C5.83203 5.92064 6.57822 6.66683 7.4987 6.66683ZM5.83203 10.0002C5.83203 9.07969 6.57822 8.3335 7.4987 8.3335C8.41917 8.3335 9.16536 9.07969 9.16536 10.0002C9.16536 10.9206 8.41917 11.6668 7.4987 11.6668C6.57822 11.6668 5.83203 10.9206 5.83203 10.0002ZM7.4987 13.3335C6.57822 13.3335 5.83203 14.0797 5.83203 15.0002C5.83203 15.9206 6.57822 16.6668 7.4987 16.6668C8.41917 16.6668 9.16536 15.9206 9.16536 15.0002C9.16536 14.0797 8.41917 13.3335 7.4987 13.3335ZM14.1654 5.00016C14.1654 5.92064 13.4192 6.66683 12.4987 6.66683C11.5782 6.66683 10.832 5.92064 10.832 5.00016C10.832 4.07969 11.5782 3.3335 12.4987 3.3335C13.4192 3.3335 14.1654 4.07969 14.1654 5.00016ZM12.4987 8.3335C11.5782 8.3335 10.832 9.07969 10.832 10.0002C10.832 10.9206 11.5782 11.6668 12.4987 11.6668C13.4192 11.6668 14.1654 10.9206 14.1654 10.0002C14.1654 9.07969 13.4192 8.3335 12.4987 8.3335ZM10.832 15.0002C10.832 14.0797 11.5782 13.3335 12.4987 13.3335C13.4192 13.3335 14.1654 14.0797 14.1654 15.0002C14.1654 15.9206 13.4192 16.6668 12.4987 16.6668C11.5782 16.6668 10.832 15.9206 10.832 15.0002Z"
4
+ fill="currentColor"
5
+ fill-rule="evenodd"
6
+ clip-rule="evenodd"
7
+ />
8
+ </svg>
@@ -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'
@@ -7,6 +8,8 @@ import process from 'node:process'
7
8
  const PACKAGE_NAME = '@retailcrm/embed-ui-v1-components'
8
9
  const DEFAULT_NEWLINE = '\n'
9
10
  const AGENTS_SECTION_HEADER = '## @retailcrm/embed-ui-v1-components'
11
+ const AGENTS_SECTION_START = '<!-- embed-ui-agents:start -->'
12
+ const AGENTS_SECTION_END = '<!-- embed-ui-agents:end -->'
10
13
 
11
14
  const HELP_TEXT = `Usage:
12
15
  npx ${PACKAGE_NAME} init-agents [target] [options]
@@ -21,6 +24,136 @@ Examples:
21
24
  npx ${PACKAGE_NAME} init-agents --force
22
25
  `
23
26
 
27
+ const toPosixPath = (value) => value.split(path.sep).join('/')
28
+
29
+ const withDotPrefix = (value) => {
30
+ if (!value || value === '.') {
31
+ return '.'
32
+ }
33
+
34
+ return value.startsWith('.') ? value : `./${value}`
35
+ }
36
+
37
+ const isPackageRoot = (directory) => {
38
+ const packageJsonPath = path.join(directory, 'package.json')
39
+
40
+ if (!fs.existsSync(packageJsonPath)) {
41
+ return false
42
+ }
43
+
44
+ try {
45
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'))
46
+
47
+ return packageJson.name === PACKAGE_NAME
48
+ } catch {
49
+ return false
50
+ }
51
+ }
52
+
53
+ const isInsideDirectory = (parent, child) => {
54
+ const relativePath = path.relative(parent, child)
55
+
56
+ return relativePath === '' || (!relativePath.startsWith('..') && !path.isAbsolute(relativePath))
57
+ }
58
+
59
+ const addNestedPackageCandidates = (start, addCandidate) => {
60
+ const packagePath = path.join('node_modules', ...PACKAGE_NAME.split('/'))
61
+ const ignoredDirectories = new Set(['.git', '.yarn', 'dist', 'node_modules'])
62
+ const queue = [path.resolve(start)]
63
+ const seen = new Set(queue)
64
+
65
+ for (let index = 0; index < queue.length; index++) {
66
+ const current = queue[index]
67
+
68
+ addCandidate(path.join(current, packagePath))
69
+
70
+ let entries = []
71
+
72
+ try {
73
+ entries = fs.readdirSync(current, { withFileTypes: true })
74
+ } catch {
75
+ continue
76
+ }
77
+
78
+ for (const entry of entries) {
79
+ if (!entry.isDirectory() || entry.name.startsWith('.') || ignoredDirectories.has(entry.name)) {
80
+ continue
81
+ }
82
+
83
+ const next = path.join(current, entry.name)
84
+
85
+ if (!seen.has(next)) {
86
+ seen.add(next)
87
+ queue.push(next)
88
+ }
89
+ }
90
+ }
91
+ }
92
+
93
+ const getCurrentPackageRoot = () => {
94
+ const packageRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..')
95
+
96
+ return isPackageRoot(packageRoot) ? packageRoot : null
97
+ }
98
+
99
+ const findPackageRoot = (target) => {
100
+ const candidates = []
101
+ const seen = new Set()
102
+
103
+ const addCandidate = (candidate) => {
104
+ const resolved = path.resolve(candidate)
105
+
106
+ if (!seen.has(resolved)) {
107
+ seen.add(resolved)
108
+ candidates.push(resolved)
109
+ }
110
+ }
111
+
112
+ const addNodeModulesCandidates = (start) => {
113
+ const packagePath = path.join('node_modules', ...PACKAGE_NAME.split('/'))
114
+ let current = path.resolve(start)
115
+
116
+ while (true) {
117
+ addCandidate(path.join(current, packagePath))
118
+
119
+ const parent = path.dirname(current)
120
+
121
+ if (parent === current) {
122
+ break
123
+ }
124
+
125
+ current = parent
126
+ }
127
+ }
128
+
129
+ addCandidate(target)
130
+ addNodeModulesCandidates(target)
131
+ addNestedPackageCandidates(target, addCandidate)
132
+
133
+ const currentPackageRoot = getCurrentPackageRoot()
134
+
135
+ if (currentPackageRoot && isInsideDirectory(target, currentPackageRoot)) {
136
+ addCandidate(currentPackageRoot)
137
+ }
138
+
139
+ const packageRoot = candidates.find(isPackageRoot)
140
+
141
+ if (!packageRoot) {
142
+ throw new Error(
143
+ `Cannot find local ${PACKAGE_NAME}. Install it in this project or run init-agents from the package workspace.`
144
+ )
145
+ }
146
+
147
+ return packageRoot
148
+ }
149
+
150
+ const createPackageDocsPath = (target) => {
151
+ const packageRoot = findPackageRoot(target)
152
+ const relativePath = path.relative(target, packageRoot)
153
+
154
+ return withDotPrefix(toPosixPath(relativePath))
155
+ }
156
+
24
157
  const parseArgs = (argv) => {
25
158
  const options = {
26
159
  command: null,
@@ -67,25 +200,33 @@ const parseArgs = (argv) => {
67
200
  return options
68
201
  }
69
202
 
70
- const createAgentsTemplate = () => {
203
+ const createAgentsTemplate = (packageDocsPath) => {
71
204
  return `# AGENTS.md
72
205
 
206
+ ${createAgentsSection(packageDocsPath)}`
207
+ }
208
+
209
+ const createAgentsSection = (packageDocsPath) => {
210
+ return `${AGENTS_SECTION_START}
73
211
  ${AGENTS_SECTION_HEADER}
74
212
 
75
213
  When working with \`${PACKAGE_NAME}\` in this project:
76
214
 
77
- 1. Read \`./node_modules/${PACKAGE_NAME}/README.md\`.
78
- 2. Then read \`./node_modules/${PACKAGE_NAME}/AGENTS.md\`.
79
- 3. Then read \`./node_modules/${PACKAGE_NAME}/docs/AI.md\`.
80
- 4. Then read \`./node_modules/${PACKAGE_NAME}/docs/COMPONENTS.md\`.
81
- 5. Then open the relevant profile from \`./node_modules/${PACKAGE_NAME}/docs/profiles/<Component>.yml\`.
82
- 6. Prefer those docs and profiles over guessing from internal implementation files.
83
- 7. Import only from documented public entrypoints:
215
+ 1. Read \`${packageDocsPath}/README.md\`.
216
+ 2. Then read \`${packageDocsPath}/AGENTS.md\`.
217
+ 3. Then read \`${packageDocsPath}/docs/AI.md\`.
218
+ 4. Then read \`${packageDocsPath}/docs/COMPONENTS.md\`.
219
+ 5. Then read \`${packageDocsPath}/docs/PROFILES.md\`.
220
+ 6. Then open relevant component profiles from \`${packageDocsPath}/docs/profiles/components/*.yml\`.
221
+ 7. For complete pages, modals, sidebars, filters, tables, or settings layouts, open the relevant
222
+ page profile from \`${packageDocsPath}/docs/profiles/pages/*.yml\`.
223
+ 8. Prefer those docs and profiles over guessing from internal implementation files.
224
+ 9. Import only from documented public entrypoints:
84
225
  - \`${PACKAGE_NAME}/remote\`
85
226
  - \`${PACKAGE_NAME}/host\`
86
227
  - \`${PACKAGE_NAME}/assets/...\`
87
- 8. Prefer \`${PACKAGE_NAME}/remote\` for extension UI code.
88
- 9. Do not import from package-internal files such as \`dist/*\`, repository-only paths, or source internals.
228
+ 10. Prefer \`${PACKAGE_NAME}/remote\` for extension UI code.
229
+ 11. Do not import from package-internal files such as \`dist/*\`, repository-only paths, or source internals.
89
230
 
90
231
  ## Suggested Reading Order
91
232
 
@@ -93,65 +234,100 @@ When working with \`${PACKAGE_NAME}\` in this project:
93
234
  2. \`AGENTS.md\`
94
235
  3. \`docs/AI.md\`
95
236
  4. \`docs/COMPONENTS.md\`
96
- 5. The relevant profile from \`docs/profiles/*.yml\`
97
- 6. \`docs/FORMAT.md\` if you need to understand profile structure
98
- 7. Storybook and public types only when no profile exists yet
99
- ` + DEFAULT_NEWLINE
237
+ 5. \`docs/PROFILES.md\`
238
+ 6. The relevant component profile from \`docs/profiles/components/*.yml\`
239
+ 7. The relevant page profile from \`docs/profiles/pages/*.yml\` for full-screen or overlay composition
240
+ 8. \`docs/FORMAT.md\` if you need to understand profile structure
241
+ 9. Public type declarations only when no profile exists yet
242
+ ${AGENTS_SECTION_END}
243
+ `
100
244
  }
101
245
 
102
- const createAgentsSection = () => {
103
- return `${AGENTS_SECTION_HEADER}
246
+ const findMarkedSectionRange = (content) => {
247
+ const start = content.indexOf(AGENTS_SECTION_START)
248
+ const end = content.indexOf(AGENTS_SECTION_END, start + AGENTS_SECTION_START.length)
104
249
 
105
- When working with \`${PACKAGE_NAME}\` in this project:
250
+ if (start === -1 && end === -1) {
251
+ return null
252
+ }
106
253
 
107
- 1. Read \`./node_modules/${PACKAGE_NAME}/README.md\`.
108
- 2. Then read \`./node_modules/${PACKAGE_NAME}/AGENTS.md\`.
109
- 3. Then read \`./node_modules/${PACKAGE_NAME}/docs/AI.md\`.
110
- 4. Then read \`./node_modules/${PACKAGE_NAME}/docs/COMPONENTS.md\`.
111
- 5. Then open the relevant profile from \`./node_modules/${PACKAGE_NAME}/docs/profiles/<Component>.yml\`.
112
- 6. Prefer those docs and profiles over guessing from internal implementation files.
113
- 7. Import only from documented public entrypoints:
114
- - \`${PACKAGE_NAME}/remote\`
115
- - \`${PACKAGE_NAME}/host\`
116
- - \`${PACKAGE_NAME}/assets/...\`
117
- 8. Prefer \`${PACKAGE_NAME}/remote\` for extension UI code.
118
- 9. Do not import from package-internal files such as \`dist/*\`, repository-only paths, or source internals.
254
+ if (start === -1 || end === -1 || end < start) {
255
+ throw new Error(`AGENTS.md contains incomplete ${PACKAGE_NAME} section markers`)
256
+ }
119
257
 
120
- ## Suggested Reading Order
258
+ return {
259
+ start,
260
+ end: end + AGENTS_SECTION_END.length,
261
+ }
262
+ }
121
263
 
122
- 1. \`README.md\`
123
- 2. \`AGENTS.md\`
124
- 3. \`docs/AI.md\`
125
- 4. \`docs/COMPONENTS.md\`
126
- 5. The relevant profile from \`docs/profiles/*.yml\`
127
- 6. \`docs/FORMAT.md\` if you need to understand profile structure
128
- 7. Storybook and public types only when no profile exists yet
129
- `
264
+ const findLegacySectionRange = (content) => {
265
+ const escapedHeader = AGENTS_SECTION_HEADER.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
266
+ const headerPattern = new RegExp(`(^|\\n)${escapedHeader}(?=\\n|$)`, 'u')
267
+ const match = headerPattern.exec(content)
268
+
269
+ if (!match) {
270
+ return null
271
+ }
272
+
273
+ const start = match.index + match[1].length
274
+ const afterHeader = content.slice(start + AGENTS_SECTION_HEADER.length)
275
+ const nextExternalHeading = /\n## (?!Suggested Reading Order\b)[^\n]*/u.exec(afterHeader)
276
+
277
+ return {
278
+ start,
279
+ end: nextExternalHeading
280
+ ? start + AGENTS_SECTION_HEADER.length + nextExternalHeading.index
281
+ : content.length,
282
+ }
130
283
  }
131
284
 
132
- const hasPackageSection = (content) => content.includes(AGENTS_SECTION_HEADER)
285
+ const hasPackageSection = (content) => {
286
+ return Boolean(findMarkedSectionRange(content) || findLegacySectionRange(content))
287
+ }
133
288
 
134
289
  const appendSection = (content, section) => {
135
290
  const trimmed = content.replace(/\s+$/u, '')
136
291
 
137
292
  if (!trimmed.length) {
138
- return `${section}${DEFAULT_NEWLINE}`
293
+ return `${section.trimEnd()}${DEFAULT_NEWLINE}`
139
294
  }
140
295
 
141
- return `${trimmed}${DEFAULT_NEWLINE}${DEFAULT_NEWLINE}${section}${DEFAULT_NEWLINE}`
296
+ return `${trimmed}${DEFAULT_NEWLINE}${DEFAULT_NEWLINE}${section.trimEnd()}${DEFAULT_NEWLINE}`
297
+ }
298
+
299
+ const replaceRange = (content, range, section) => {
300
+ const before = content.slice(0, range.start).replace(/\s+$/u, '')
301
+ const after = content.slice(range.end).replace(/^\s+/u, '')
302
+ const parts = []
303
+
304
+ if (before) {
305
+ parts.push(before)
306
+ }
307
+
308
+ parts.push(section.trimEnd())
309
+
310
+ if (after) {
311
+ parts.push(after)
312
+ }
313
+
314
+ return `${parts.join(`${DEFAULT_NEWLINE}${DEFAULT_NEWLINE}`)}${DEFAULT_NEWLINE}`
142
315
  }
143
316
 
144
317
  const replaceSection = (content, section) => {
145
- const escapedHeader = AGENTS_SECTION_HEADER.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
146
- const sectionPattern = new RegExp(`${escapedHeader}[\\s\\S]*?(?=\\n##\\s|$)`, 'u')
318
+ const markedRange = findMarkedSectionRange(content)
319
+
320
+ if (markedRange) {
321
+ return replaceRange(content, markedRange, section)
322
+ }
323
+
324
+ const legacyRange = findLegacySectionRange(content)
147
325
 
148
- if (!sectionPattern.test(content)) {
149
- return appendSection(content, section)
326
+ if (legacyRange) {
327
+ return replaceRange(content, legacyRange, section)
150
328
  }
151
329
 
152
- return content
153
- .replace(sectionPattern, section.trimEnd())
154
- .replace(/\s+$/u, '') + DEFAULT_NEWLINE
330
+ return appendSection(content, section)
155
331
  }
156
332
 
157
333
  const initAgents = (target, force) => {
@@ -166,10 +342,11 @@ const initAgents = (target, force) => {
166
342
  }
167
343
 
168
344
  const agentsPath = path.join(target, 'AGENTS.md')
169
- const section = createAgentsSection()
345
+ const packageDocsPath = createPackageDocsPath(target)
346
+ const section = createAgentsSection(packageDocsPath)
170
347
 
171
348
  if (!fs.existsSync(agentsPath)) {
172
- fs.writeFileSync(agentsPath, createAgentsTemplate(), 'utf8')
349
+ fs.writeFileSync(agentsPath, createAgentsTemplate(packageDocsPath), 'utf8')
173
350
 
174
351
  console.log(`AGENTS.md was created at ${agentsPath}`)
175
352
  console.log('Next step: review it and adjust project-specific rules if needed.')
@@ -27,7 +27,8 @@ const hasAgentsFile = fs.existsSync(agentsPath)
27
27
 
28
28
  console.log('')
29
29
  console.log(`[${PACKAGE_NAME}] AI docs are available in node_modules/${PACKAGE_NAME}/README.md, AGENTS.md, and docs`)
30
- console.log(`[${PACKAGE_NAME}] Start with README.md, AGENTS.md, docs/AI.md, docs/COMPONENTS.md, and docs/profiles/*.yml`)
30
+ console.log(`[${PACKAGE_NAME}] Start with README.md, AGENTS.md, docs/AI.md, docs/COMPONENTS.md, and docs/PROFILES.md`)
31
+ console.log(`[${PACKAGE_NAME}] Component profiles live in docs/profiles/components, page profiles live in docs/profiles/pages`)
31
32
 
32
33
  if (!hasAgentsFile) {
33
34
  console.log(`[${PACKAGE_NAME}] To scaffold AGENTS.md for this project, run:`)