@sberbusiness/triplex-next-mcp-server 1.42.0-beta → 1.44.0-beta

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 (35) hide show
  1. package/bundle/components/AlertProcess.md +3 -2
  2. package/bundle/components/BodyPage.md +72 -4
  3. package/bundle/components/Button.md +1 -0
  4. package/bundle/components/Checkbox.md +7 -1
  5. package/bundle/components/CheckboxTreeExtended.md +149 -248
  6. package/bundle/components/CheckboxXGroup.md +2 -0
  7. package/bundle/components/CheckboxYGroup.md +7 -2
  8. package/bundle/components/ChipGroup.md +195 -126
  9. package/bundle/components/CollapsibleTreeExtended.md +6 -1
  10. package/bundle/components/DatePickerExtended.md +409 -262
  11. package/bundle/components/ExpandAnimation.md +263 -218
  12. package/bundle/components/Footer.md +235 -278
  13. package/bundle/components/Island.md +36 -1
  14. package/bundle/components/LightBox.md +14 -3
  15. package/bundle/components/MediaWidth.md +7 -1
  16. package/bundle/components/Notification.md +21 -3
  17. package/bundle/components/Overlay.md +24 -1
  18. package/bundle/components/Pagination.md +12 -13
  19. package/bundle/components/SliderExtended.md +358 -222
  20. package/bundle/components/TableBasic.md +2294 -0
  21. package/bundle/components/TabsExtended.md +380 -194
  22. package/bundle/components/Tag.md +259 -78
  23. package/bundle/components/TopOverlay.md +366 -90
  24. package/bundle/components/TreeView.md +343 -166
  25. package/bundle/components/TreeViewNode.md +436 -0
  26. package/bundle/components/UnorderedList.md +254 -0
  27. package/bundle/components/UnorderedListExtended.md +255 -0
  28. package/bundle/components/WindowResizeListener.md +249 -0
  29. package/bundle/guides/commits.md +121 -15
  30. package/bundle/guides/stories.md +1 -1
  31. package/bundle/manifest.json +46 -20
  32. package/bundle/release-notes/1.43.0.mdx +87 -0
  33. package/bundle/release-notes/1.44.0.mdx +120 -0
  34. package/bundle/release-notes/1.45.0.mdx +7 -0
  35. package/package.json +1 -1
@@ -0,0 +1,249 @@
1
+ ---
2
+ component: WindowResizeListener
3
+ category: WindowResizeListener
4
+ related: [MediaWidth]
5
+ tokens: []
6
+ stories: stories/WindowResizeListener/WindowResizeListener.stories.tsx
7
+ version: "1.0"
8
+ ---
9
+
10
+ # WindowResizeListener
11
+
12
+ ## Назначение
13
+
14
+ Сервисный headless-компонент. Пока смонтирован, слушает событие `resize` на
15
+ `window` и вызывает `onResize`, но не чаще, чем раз в `throttleDelay`
16
+ миллисекунд. Собственной разметки не рендерит: `children` выводятся как есть,
17
+ без обёртки; без `children` не рендерит ничего.
18
+
19
+ Используй когда: при изменении размеров окна нужно выполнить императивное
20
+ действие — пересчитать размеры/отступы по замеренному DOM, перепозиционировать
21
+ оверлей, сбросить кэш измерений.
22
+
23
+ Не используй когда:
24
+ - Нужно отрендерить **другое дерево** компонентов на другой ширине — для этого
25
+ есть `MediaWidth` / `MobileView`, они слушают `MediaQueryList`, а не поток
26
+ событий `resize`.
27
+ - Нужно булево значение «широкий/узкий экран» для props или условной разметки —
28
+ используй `useMatchMedia` (`src/components/MediaWidth/useMatchMedia.ts`) или
29
+ `useMobileView`.
30
+ - Отслеживать нужно размер конкретного элемента, а не окна — окно может не
31
+ меняться, а элемент — да (открылась панель, изменился контент). Для этого в
32
+ библиотеке используется `useResizeDetector` из `react-resize-detector`
33
+ (пример — `LightBoxContent`).
34
+ - Разница чисто визуальная (отступы, шрифт, раскладка) — это дешевле решается
35
+ медиа-запросом в `*.module.less`, без JS-обработчика на каждое событие.
36
+
37
+ ---
38
+
39
+ ## Варианты и props
40
+
41
+ ### Обязательные props
42
+
43
+ | Prop | Тип | Описание |
44
+ |---|---|---|
45
+ | `onResize` | `(event: UIEvent) => void` | Вызывается на `resize` окна. Получает нативный `UIEvent` (не React SyntheticEvent). Полезной нагрузки в событии нет — актуальные размеры читаются из `window.innerWidth` / `innerHeight` или замером DOM |
46
+
47
+ ### Опциональные props
48
+
49
+ | Prop | Тип | По умолчанию | Описание |
50
+ |---|---|---|---|
51
+ | `throttleDelay` | `number` | `100` | Минимальный интервал между вызовами `onResize`, в миллисекундах |
52
+ | `children` | `React.ReactNode` | — | Рендерится как есть. Компонент не оборачивает содержимое и никак на него не влияет — вложение нужно только для читаемости кода |
53
+
54
+ ### Особенности поведения
55
+
56
+ - Слушатель навешивается в `useEffect`, поэтому `window` не трогается во время
57
+ рендера — компонент **SSR-safe** (в отличие от семейства `MediaWidth`, которое
58
+ вызывает `window.matchMedia` на первом рендере).
59
+ - Троттлинг — `throttle` из `lodash-es` с настройками по умолчанию:
60
+ **leading + trailing**. Первое событие серии обрабатывается синхронно, все
61
+ последующие внутри окна схлопываются в один отложенный вызов в конце окна.
62
+ Одиночное событие даёт ровно один вызов; если внутри окна пришли ещё события,
63
+ в конце окна добавляется trailing-вызов.
64
+ - **Обработчик и задержка входят в зависимости эффекта.** При смене ссылки
65
+ `onResize` или значения `throttleDelay` слушатель снимается и навешивается
66
+ заново, а троттлинг начинается с чистого листа (новое leading-окно). Если
67
+ передать инлайновую стрелку, переподписка будет происходить на **каждый
68
+ рендер**, и троттлинг фактически перестанет ограничивать частоту вызовов.
69
+ Оборачивай обработчик в `useCallback` (или храни его вне компонента).
70
+ - При размонтировании слушатель снимается, а отложенный trailing-вызов
71
+ отменяется через `cancel()` — `removeEventListener` сам по себе его
72
+ не отменяет, и колбэк сработал бы уже после размонтирования.
73
+ - Компонент не вызывает `preventDefault` / `stopPropagation` (событие `resize`
74
+ не отменяемо) и не подмешивает в `onResize` собственные данные о размерах.
75
+ - Несколько смонтированных `WindowResizeListener` работают независимо, каждый со
76
+ своим окном троттлинга.
77
+
78
+ ---
79
+
80
+ ## Дизайн-токены
81
+
82
+ Собственных стилей и CSS-переменных нет — компонент не рендерит разметку.
83
+
84
+ ---
85
+
86
+ ## Инварианты
87
+
88
+ - **Без `forwardRef` — осознанное исключение** из общего правила библиотеки:
89
+ компонент не рендерит собственный host-элемент, форвардить `ref` некуда. Не
90
+ добавлять и не убирать без отдельного решения.
91
+ - **Имена и типы props `children`, `onResize`, `throttleDelay`** и значение по
92
+ умолчанию `throttleDelay = 100` — публичное API, не менять. Интерфейс
93
+ `IWindowResizeListenerProps` экспортируется из barrel — переименование будет
94
+ breaking change.
95
+ - **`return children ?? null`** — falsy-`children` (`0`, `""`) осознанно
96
+ рендерятся; `??`, а не `||` (у соседнего `KeyDownListener` обратная
97
+ договорённость — там `||`). Возврат `null` вместо `undefined` нужен для React
98
+ 17: там компонент, вернувший `undefined`, роняет рендер.
99
+ - **Зависимости эффекта `[onResize, throttleDelay]`** — не «оптимизировать»
100
+ переносом обработчика в `ref`: сейчас смена обработчика сбрасывает окно
101
+ троттлинга, и это наблюдаемое поведение у потребителей.
102
+ - **`throttledResize.cancel()` в cleanup** — не удалять: без него отложенный вызов
103
+ срабатывает после размонтирования (тест `cancels the pending trailing call on
104
+ unmount`).
105
+ - Реализация остаётся React 17-совместимой (без `useId`,
106
+ `useSyncExternalStore` и прочих React 18-only API): код синхронизируется
107
+ в `release-0`.
108
+
109
+ ---
110
+
111
+ ## Accessibility
112
+
113
+ - Собственной ARIA-семантики нет — компонент прозрачен для accessibility-дерева
114
+ и не рендерит фокусируемых элементов.
115
+ - `resize` окна возникает и при зуме страницы, и при появлении экранной
116
+ клавиатуры на мобильных. Обработчик не должен перебрасывать фокус или
117
+ сбрасывать состояние формы — для пользователя, увеличившего масштаб, это
118
+ выглядит как потеря контекста.
119
+
120
+ ---
121
+
122
+ ## Связанные компоненты
123
+
124
+ - `MediaWidth` (`src/components/MediaWidth/`) — альтернатива для декларативного
125
+ случая: рендерит одну из двух веток по медиа-запросу, а не даёт колбэк на поток
126
+ событий. Там же `useMatchMedia` (булево значение для условной разметки) и
127
+ `MobileView` (частный случай мобильной границы). Правило выбора: нужно
128
+ **что-то посчитать/сделать** на ресайз — `WindowResizeListener`; нужно
129
+ **что-то показать** на определённой ширине — `MediaWidth`.
130
+ - `KeyDownListener` (`src/components/KeyDownListener/`) — headless-слушатель того
131
+ же покроя, но для `keydown` на `window`. Похожий контракт по `children` (рендер
132
+ как есть, без обёртки); отличие — обработка falsy-`children`, см. «Инварианты».
133
+
134
+ ### Потребители внутри библиотеки
135
+
136
+ - `LightBoxContent` (`src/components/LightBox/LightBoxContent.tsx`) — пересчёт
137
+ верхнего отступа контента при изменении размеров окна. Обработчик
138
+ (`updateStyleWithTimeout`) обёрнут в `useCallback`, поэтому переподписки на
139
+ каждый рендер не происходит. Слушатель размеров самого контента там сделан
140
+ отдельно, через `useResizeDetector`.
141
+
142
+ В unit-тестах потребителей компонент удобно мокать целиком — как в
143
+ `src/components/LightBox/__tests__/LightBoxContent.test.tsx`.
144
+
145
+ ---
146
+
147
+ ## Stories
148
+
149
+ Основные истории: `stories/WindowResizeListener/WindowResizeListener.stories.tsx`
150
+ Файлы примеров: `stories/WindowResizeListener/examples/`
151
+
152
+ | Story | Example file | Что демонстрирует |
153
+ |---|---|---|
154
+ | `Playground` | `Playground.tsx` | Интерактивный подбор `throttleDelay`, счётчик срабатываний `onResize` и текущая ширина окна |
155
+ | `Default` | `Default.tsx` | Минимальный пример: обработчик в `useCallback` читает `window.innerWidth` / `innerHeight` |
156
+ | `ThrottleDelay` | `ThrottleDelay.tsx` | Два слушателя с разной задержкой (100 мс и 1000 мс) и их счётчики вызовов |
157
+
158
+ Набор целиком исключён из скриншот-тестов (`testRunner: { skip: true }` в `meta`):
159
+ собственной разметки компонент не рендерит, на скриншот попадала бы только
160
+ обвязка примеров. Baseline-файлов в `__screenshots__/` для этого набора быть не
161
+ должно. Поведение слушателя покрыто unit-тестами.
162
+
163
+ ---
164
+
165
+ ## История изменений
166
+
167
+ | Дата | Изменение |
168
+ |---|---|
169
+ | 2026-08-18 | Создан документ. AI-рефакторинг (TRI-104): JSDoc на props и компоненте, интерфейс `IWindowResizeListenerProps` стал экспортируемым (аддитивно), `return children ?? null` вместо `return children` (React 17-safe), убрано лишнее опциональное обращение `cancel?.()`, добавлены unit-тесты (10 кейсов: рендер `children`, троттлинг с дефолтной и заданной задержкой, отписка и отмена trailing-вызова при размонтировании, переподписка при смене `onResize` / `throttleDelay`) и набор stories по modern pattern. Публичный API не изменён (имена и типы props, дефолт `throttleDelay = 100`, barrel-экспорты; `forwardRef` по-прежнему осознанно отсутствует). |
170
+
171
+ ---
172
+
173
+ ## Примеры использования
174
+
175
+ ### Default
176
+
177
+ `stories/WindowResizeListener/examples/Default.tsx`
178
+
179
+ ```tsx
180
+ import React, { useCallback, useState } from "react";
181
+ import { WindowResizeListener } from "@sberbusiness/triplex-next";
182
+
183
+ const getWindowSize = () =>
184
+ typeof window === "undefined" ? { width: 0, height: 0 } : { width: window.innerWidth, height: window.innerHeight };
185
+
186
+ export const Default = () => {
187
+ // При рендере на сервере window недоступен — стартовое значение берётся только в браузере.
188
+ const [windowSize, setWindowSize] = useState(getWindowSize);
189
+
190
+ // Стабильная ссылка на обработчик: при её смене слушатель переподписывается заново.
191
+ const handleResize = useCallback(() => {
192
+ setWindowSize(getWindowSize());
193
+ }, []);
194
+
195
+ return (
196
+ <WindowResizeListener onResize={handleResize}>
197
+ <div style={{ display: "flex", flexDirection: "column", gap: "16px", maxWidth: "400px" }}>
198
+ <div>Измените размер окна браузера, чтобы обновить значения.</div>
199
+ <div style={{ border: "1px dashed rgb(125, 131, 138)", borderRadius: "4px", padding: "16px" }}>
200
+ Размер окна: {windowSize.width} × {windowSize.height}
201
+ </div>
202
+ </div>
203
+ </WindowResizeListener>
204
+ );
205
+ };
206
+ ```
207
+
208
+ ### ThrottleDelay
209
+
210
+ `stories/WindowResizeListener/examples/ThrottleDelay.tsx`
211
+
212
+ ```tsx
213
+ import React, { useCallback, useState } from "react";
214
+ import { WindowResizeListener } from "@sberbusiness/triplex-next";
215
+
216
+ interface IResizeCounterProps {
217
+ throttleDelay: number;
218
+ }
219
+
220
+ const ResizeCounter = ({ throttleDelay }: IResizeCounterProps) => {
221
+ const [resizeCount, setResizeCount] = useState(0);
222
+
223
+ const handleResize = useCallback(() => {
224
+ setResizeCount((prevCount) => prevCount + 1);
225
+ }, []);
226
+
227
+ return (
228
+ <WindowResizeListener onResize={handleResize} throttleDelay={throttleDelay}>
229
+ <div>
230
+ <div style={{ marginBottom: "8px", fontSize: "16px", fontWeight: "700" }}>
231
+ throttleDelay: {throttleDelay}ms
232
+ </div>
233
+ <div style={{ border: "1px dashed rgb(125, 131, 138)", borderRadius: "4px", padding: "16px" }}>
234
+ Срабатываний onResize: {resizeCount}
235
+ </div>
236
+ </div>
237
+ </WindowResizeListener>
238
+ );
239
+ };
240
+
241
+ export const ThrottleDelay = () => (
242
+ <div style={{ display: "flex", flexDirection: "column", gap: "16px", maxWidth: "400px" }}>
243
+ <div>Измените размер окна браузера — чем больше задержка, тем реже вызывается обработчик.</div>
244
+ <ResizeCounter throttleDelay={100} />
245
+ <ResizeCounter throttleDelay={1000} />
246
+ </div>
247
+ );
248
+ ```
249
+
@@ -56,11 +56,14 @@ TRI-21-alert-ai-ready
56
56
  `docs/human/release.md`. Прямой push в `release-0` проверяется CI:
57
57
  `ci.yml` триггерится на `push: branches: [release-0]`.
58
58
 
59
- **Единственное исключение для агента** — релизный коммит `release-react17`
60
- (бамп версии + release notes): он тоже пушится в `release-0` напрямую, без
61
- PR. Прогон CI на него стартует, но дождаться его нельзя — GitHub Release
62
- создаётся сразу после push. Поэтому исключение компенсируется обязательными
63
- локальными гейтами (`tsc`, `test-unit`, `build`).
59
+ **Единственное исключение** — релизный коммит (бамп версии + release notes):
60
+ он тоже попадает в `release-0` напрямую, без PR. В еженедельном релизе его
61
+ делает [`release-weekly.yml`](../../.github/workflows/release-weekly.yml),
62
+ при ручном выпуске — skill `release-react17`. Прогон CI на этот коммит
63
+ стартует, но дождаться его нельзя: релиз создаётся сразу после push. Поэтому
64
+ исключение компенсируется гейтами перед пушем — `npm run test-unit`
65
+ и `npm run build` (последний в `prebuild` гоняет `tsc -p tsconfig.build.json`;
66
+ полный `tsc` гейтом быть не может — он даёт давние ошибки в `stories/`).
64
67
 
65
68
  ---
66
69
 
@@ -86,6 +89,24 @@ TRI-21 Alert: AI refactoring + unit-тесты
86
89
  - Тело коммита опционально (для сложных изменений).
87
90
  - Язык: русский или английский — не смешивать в одном коммите.
88
91
 
92
+ **Исключение — релизные коммиты еженедельного релиза.** Их делает
93
+ [`release-weekly.yml`](../../.github/workflows/release-weekly.yml) в GitHub
94
+ Actions, и они идут **без префикса задачи**:
95
+
96
+ ```text
97
+ Подготовка релиза 0.44.0
98
+ Подготовка релиза 1.44.0
99
+ ```
100
+
101
+ Причина техническая: у Actions нет доступа к Linear, номер задачи взять
102
+ неоткуда, а выдумывать его нельзя. Связь с трекером даёт skill `release-auto`
103
+ — он заводит задачу «Релиз 1.Y.0 / 0.Y.0» по итогам прогона и складывает
104
+ туда ссылки на релизы. Коммит машинный, его авторство видно по автору
105
+ (`dudim-ai`), поэтому потеря префикса не мешает разбору истории.
106
+
107
+ При **ручном** выпуске (`/release`) префикс обязателен, как обычно: там
108
+ задача Linear заводится до начала работы.
109
+
89
110
  ---
90
111
 
91
112
  ## Когда запускать линтер
@@ -140,7 +161,8 @@ npx prettier --write src/components/Button/Button.tsx
140
161
 
141
162
  1. делает коммит по конвенциям этого файла (skill `commit-component`);
142
163
  2. пушит ветку;
143
- 3. создаёт PR (см. «PR-воркфлоу»);
164
+ 3. дожидается PR от workflow `auto-pr.yml` (см. «PR-воркфлоу»; сам
165
+ `gh pr create` в ветках `TRI-*` не вызывает);
144
166
  4. если менялись stories или визуал компонентов — обновляет baseline-скриншоты
145
167
  через skill `update-visual-baselines` (CI-workflow «Update Visual
146
168
  Snapshots» + чистка orphan-скриншотов);
@@ -161,9 +183,9 @@ npx prettier --write src/components/Button/Button.tsx
161
183
 
162
184
  ## GitHub-операции от аккаунта бота
163
185
 
164
- Автоматические GitHub-операции (создание PR, комментарии в PR, запуск
165
- workflow, авторство коммитов автофинала) выполняются от отдельного
166
- machine-аккаунта, если у разработчика задан его токен:
186
+ Автоматические GitHub-операции (комментарии в PR, запуск workflow,
187
+ авторство коммитов автофинала) выполняются от отдельного machine-аккаунта,
188
+ если у разработчика задан его токен:
167
189
 
168
190
  ```bash
169
191
  # fine-grained PAT бота: contents:write, pull-requests:write, actions:write
@@ -171,11 +193,18 @@ export TRIPLEX_BOT_GH_TOKEN=... # в ~/.zshenv (не ~/.zshrc — агент
171
193
  # в неинтерактивном shell), НЕ в репозитории
172
194
  ```
173
195
 
196
+ Тот же PAT хранится как repository secret `DUDIM_AI_GH_TOKEN` — его
197
+ использует workflow `auto-pr.yml`, который создаёт PR для веток `TRI-*`
198
+ (см. «PR-воркфлоу»). Благодаря этому автор PR один и тот же независимо от
199
+ того, где шла сессия агента — локально или в облаке. При ротации PAT
200
+ обнови оба места: `~/.zshenv` и secret
201
+ (`gh secret set DUDIM_AI_GH_TOKEN --body "$TRIPLEX_BOT_GH_TOKEN"`).
202
+
174
203
  **Паттерн для агентов** — в начале Bash-вызова с командами `gh`:
175
204
 
176
205
  ```bash
177
206
  if [ -n "$TRIPLEX_BOT_GH_TOKEN" ]; then export GH_TOKEN="$TRIPLEX_BOT_GH_TOKEN"; fi
178
- gh pr create ... # выполнится от бота; без токена — от разработчика (fallback)
207
+ gh pr comment ... # выполнится от бота; без токена — от разработчика (fallback)
179
208
  ```
180
209
 
181
210
  **Авторство коммитов автофинала** (identity бота выводится из токена,
@@ -203,20 +232,97 @@ fi
203
232
  - Действия в Linear выполняются от сессии разработчика — бот на них
204
233
  не распространяется.
205
234
 
235
+ ### Облачные сессии: подмена токена прокси
236
+
237
+ В облачных сессиях (routines на claude.ai) запросы к `api.github.com`
238
+ идут **не** с `TRIPLEX_BOT_GH_TOKEN`: egress-прокси подменяет авторизацию
239
+ на токен GitHub App `claude` (user-to-server, identity — аккаунт
240
+ разработчика). Паттерн выше при этом не ломается — просто действующие
241
+ права определяет прокси, а не PAT. Как распознать:
242
+
243
+ - `gh api user` возвращает аккаунт разработчика, хотя в env лежит токен
244
+ бота;
245
+ - текст 403 — «Resource not accessible by **integration**» или «not
246
+ permitted for this session type / through this proxy» (у fine-grained
247
+ PAT было бы «…by personal access token»).
248
+
249
+ Что доступно из облака — проверено зондами TRI-117 (2026-08-14) и TRI-119
250
+ (2026-08-21):
251
+
252
+ | Операция | Из облака |
253
+ |---|---|
254
+ | `git push` ветки, включая защищённый `main` | ✅ |
255
+ | Создание и мерж PR, комментарии | ✅ |
256
+ | Чтение REST и Actions | ✅ |
257
+ | Диспатч нерелизных workflow (`visual-update.yml`) | ✅ |
258
+ | `git push` тега | ❌ `RPC failed; HTTP 403` |
259
+ | `POST /git/refs`, `PATCH /git/refs/heads/*` | ❌ |
260
+ | `gh release create` | ❌ |
261
+ | `gh workflow run release.yml`, `repository_dispatch` | ❌ |
262
+ | Удаление веток и тегов | ❌ |
263
+
264
+ Отказы приходят с текстом `Write access to this GitHub API path is not
265
+ permitted through this proxy` — это ограничение прокси, а не прав токена
266
+ и не настроек репозитория. Менять branch protection бесполезно.
267
+
268
+ **Следствие для релиза:** выпустить его из облачной сессии нельзя ни одним
269
+ маршрутом. Поэтому механика релиза живёт в GitHub Actions
270
+ (`.github/workflows/release-weekly.yml`), расписание держит сам GitHub, а
271
+ за облачной routine остаётся отчёт — см.
272
+ `.agents/skills/release-auto/SKILL.md`.
273
+
206
274
  ---
207
275
 
208
276
  ## PR-воркфлоу
209
277
 
210
- **Работа по задаче Linear:** после коммита агент сам пушит ветку и создаёт PR:
278
+ **Работа по задаче Linear:** PR для веток `TRI-*` создаёт workflow
279
+ `auto-pr.yml` (триггер `on: push`) от аккаунта бота — secret
280
+ `DUDIM_AI_GH_TOKEN`. Так автор PR не зависит от среды сессии: локальный
281
+ `gh pr create` шёл бы от PAT бота, а облачный — от GitHub App `claude`
282
+ (прокси подменяет авторизацию, см. «Облачные сессии»). Агент **не вызывает
283
+ `gh pr create` в ветках `TRI-*`** — иначе облачная сессия успеет создать
284
+ PR от `claude[bot]` раньше workflow.
285
+
286
+ Финальный коммит — это и есть источник PR: заголовок берётся из первой
287
+ строки (`TRI-XXX Краткое описание`), описание — из тела коммита. Поэтому
288
+ в автофинале тело коммита обязательно и содержит описание PR
289
+ («Что сделано» / «Как проверить»).
211
290
 
212
291
  ```bash
213
292
  git push -u origin TRI-XXX-feature-name
214
- gh pr create \
215
- --title "TRI-XXX Краткое описание" \
216
- --body "## Что сделано\n- ...\n\n## Как проверить\n- ..."
293
+ # PR создаст auto-pr.yml через ~20–60 с; дождись его появления:
294
+ for i in $(seq 1 12); do
295
+ pr_url=$(gh pr list --head "TRI-XXX-feature-name" --base main --state open \
296
+ --json url --jq '.[0].url // empty') && [ -n "$pr_url" ] && break
297
+ sleep 10
298
+ done
299
+ echo "${pr_url:-PR не появился}"
217
300
  ```
218
301
 
219
- После создания PR финал продолжается автоматически: skill
302
+ Если PR не появился за ~2 минуты — проверь прогон workflow именно для
303
+ текущего коммита (не по ветке: `--limit 1` по ветке может показать прогон
304
+ предыдущего пуша):
305
+ `gh run list --workflow=auto-pr.yml --commit $(git rev-parse HEAD) --limit 1`.
306
+ Дальше по статусу:
307
+
308
+ - `queued` / `in_progress` — прогон ещё идёт, продолжай ждать;
309
+ - `completed` + `success` без PR — сработал guard (маркер `[no-pr]`,
310
+ subject не по формату `TRI-XXX ...` или ветка без новых коммитов
311
+ относительно `main`) — штатное завершение без PR, fallback не нужен;
312
+ - `completed` + `failure` или прогона нет (например, протух secret) —
313
+ fallback.
314
+ Fallback — прежняя схема: `gh pr create` с паттерном bot-токена из
315
+ раздела выше.
316
+ Fallback безопасен: раз workflow PR не создал, гонки нет. В облачной
317
+ сессии fallback-PR будет от `claude[bot]` (прокси подменит PAT — см.
318
+ «Облачные сессии») — это осознанная деградация, лучше PR от app'а, чем
319
+ отсутствие PR.
320
+
321
+ Обход автосоздания (WIP-пуш ветки `TRI-*` без PR): добавь маркер `[no-pr]`
322
+ в первую строку HEAD-коммита. Коммиты не по формату `TRI-XXX ...`
323
+ (например, `chore: ...`) PR также не создают.
324
+
325
+ После появления PR финал продолжается автоматически: skill
220
326
  `update-visual-baselines` (если менялись stories/визуал) и skill
221
327
  `finish-task` — комментарий-резюме в задаче Linear и проверка линковки PR
222
328
  (GitHub-интеграция Linear подхватит PR по `TRI-XXX` в имени ветки).
@@ -180,7 +180,7 @@ Playground показывает только те props, которые реал
180
180
 
181
181
  ### Когда не создавать Playground
182
182
 
183
- Если у компонента нет настраиваемых props (только `children` и стандартные HTML-атрибуты), Playground не создаётся — нечего класть в Controls. Типичный случай: контейнер-обёртка вроде `ListItem`, `ListItemControls`, `ChipGroup`.
183
+ Если у компонента нет настраиваемых props (только `children` и стандартные HTML-атрибуты), Playground не создаётся — нечего класть в Controls. Типичный случай: контейнер-обёртка вроде `ListItem`, `ListItemControls`.
184
184
 
185
185
  В этом случае:
186
186
 
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
- "triplexVersion": "1.42.0",
4
- "generatedAt": "2026-08-14T12:59:51.290Z",
3
+ "triplexVersion": "1.44.0",
4
+ "generatedAt": "2026-08-28T11:32:35.105Z",
5
5
  "components": [
6
6
  {
7
7
  "name": "AbstractTree",
@@ -138,7 +138,7 @@
138
138
  },
139
139
  {
140
140
  "name": "CheckboxTreeExtended",
141
- "path": "src/components/CheckboxTreeExtended/CheckboxTreeExtended-AI.md",
141
+ "path": "src/components/CheckboxTreeExtended/CheckboxTreeExtended-ai.md",
142
142
  "file": "components/CheckboxTreeExtended.md",
143
143
  "ai_ready": true
144
144
  },
@@ -162,7 +162,7 @@
162
162
  },
163
163
  {
164
164
  "name": "ChipGroup",
165
- "path": "src/components/ChipGroup/ChipGroup-AI.md",
165
+ "path": "src/components/ChipGroup/ChipGroup-ai.md",
166
166
  "file": "components/ChipGroup.md",
167
167
  "ai_ready": true
168
168
  },
@@ -210,7 +210,7 @@
210
210
  },
211
211
  {
212
212
  "name": "DatePickerExtended",
213
- "path": "src/components/DatePickerExtended/DatePickerExtended-AI.md",
213
+ "path": "src/components/DatePickerExtended/DatePickerExtended-ai.md",
214
214
  "file": "components/DatePickerExtended.md",
215
215
  "ai_ready": true
216
216
  },
@@ -258,7 +258,7 @@
258
258
  },
259
259
  {
260
260
  "name": "ExpandAnimation",
261
- "path": "src/components/ExpandAnimation/ExpandAnimation-AI.md",
261
+ "path": "src/components/ExpandAnimation/ExpandAnimation-ai.md",
262
262
  "file": "components/ExpandAnimation.md",
263
263
  "ai_ready": true
264
264
  },
@@ -271,7 +271,7 @@
271
271
  },
272
272
  {
273
273
  "name": "Footer",
274
- "path": "src/components/Footer/Footer-AI.md",
274
+ "path": "src/components/Footer/Footer-ai.md",
275
275
  "file": "components/Footer.md",
276
276
  "ai_ready": true
277
277
  },
@@ -608,7 +608,7 @@
608
608
  },
609
609
  {
610
610
  "name": "SliderExtended",
611
- "path": "src/components/SliderExtended/SliderExtended-AI.md",
611
+ "path": "src/components/SliderExtended/SliderExtended-ai.md",
612
612
  "file": "components/SliderExtended.md",
613
613
  "ai_ready": true
614
614
  },
@@ -678,6 +678,12 @@
678
678
  "file": "components/Table.md",
679
679
  "ai_ready": true
680
680
  },
681
+ {
682
+ "name": "TableBasic",
683
+ "path": "src/components/Table/TableBasic-ai.md",
684
+ "file": "components/TableBasic.md",
685
+ "ai_ready": true
686
+ },
681
687
  {
682
688
  "name": "Tabs",
683
689
  "path": "src/components/Tabs/Tabs-AI.md",
@@ -686,7 +692,7 @@
686
692
  },
687
693
  {
688
694
  "name": "TabsExtended",
689
- "path": "src/components/TabsExtended/TabsExtended-AI.md",
695
+ "path": "src/components/TabsExtended/TabsExtended-ai.md",
690
696
  "file": "components/TabsExtended.md",
691
697
  "ai_ready": true
692
698
  },
@@ -698,7 +704,7 @@
698
704
  },
699
705
  {
700
706
  "name": "Tag",
701
- "path": "src/components/Tag/Tag-AI.md",
707
+ "path": "src/components/Tag/Tag-ai.md",
702
708
  "file": "components/Tag.md",
703
709
  "ai_ready": true
704
710
  },
@@ -752,16 +758,22 @@
752
758
  },
753
759
  {
754
760
  "name": "TopOverlay",
755
- "path": "src/components/TopOverlay/TopOverlay-AI.md",
761
+ "path": "src/components/TopOverlay/TopOverlay-ai.md",
756
762
  "file": "components/TopOverlay.md",
757
763
  "ai_ready": true
758
764
  },
759
765
  {
760
766
  "name": "TreeView",
761
- "path": "src/components/TreeView/TreeView-AI.md",
767
+ "path": "src/components/TreeView/TreeView-ai.md",
762
768
  "file": "components/TreeView.md",
763
769
  "ai_ready": true
764
770
  },
771
+ {
772
+ "name": "TreeViewNode",
773
+ "path": "src/components/TreeView/TreeViewNode-ai.md",
774
+ "file": "components/TreeViewNode.md",
775
+ "ai_ready": true
776
+ },
765
777
  {
766
778
  "name": "Triggers",
767
779
  "path": "src/components/Triggers/Triggers-AI.md",
@@ -777,10 +789,15 @@
777
789
  },
778
790
  {
779
791
  "name": "UnorderedList",
780
- "path": "src/components/UnorderedList",
781
- "file": null,
782
- "ai_ready": false,
783
- "storiesPath": "stories/UnorderedList.stories.tsx"
792
+ "path": "src/components/UnorderedList/UnorderedList-ai.md",
793
+ "file": "components/UnorderedList.md",
794
+ "ai_ready": true
795
+ },
796
+ {
797
+ "name": "UnorderedListExtended",
798
+ "path": "src/components/UnorderedListExtended/UnorderedListExtended-ai.md",
799
+ "file": "components/UnorderedListExtended.md",
800
+ "ai_ready": true
784
801
  },
785
802
  {
786
803
  "name": "UploadZone",
@@ -791,10 +808,9 @@
791
808
  },
792
809
  {
793
810
  "name": "WindowResizeListener",
794
- "path": "src/components/WindowResizeListener",
795
- "file": null,
796
- "ai_ready": false,
797
- "storiesPath": null
811
+ "path": "src/components/WindowResizeListener/WindowResizeListener-ai.md",
812
+ "file": "components/WindowResizeListener.md",
813
+ "ai_ready": true
798
814
  },
799
815
  {
800
816
  "name": "ListItemTable",
@@ -1052,6 +1068,16 @@
1052
1068
  "file": "release-notes/1.43.0.mdx",
1053
1069
  "path": "stories/release-notes/v1/1.43.0.mdx"
1054
1070
  },
1071
+ {
1072
+ "version": "1.44.0",
1073
+ "file": "release-notes/1.44.0.mdx",
1074
+ "path": "stories/release-notes/v1/1.44.0.mdx"
1075
+ },
1076
+ {
1077
+ "version": "1.45.0",
1078
+ "file": "release-notes/1.45.0.mdx",
1079
+ "path": "stories/release-notes/v1/1.45.0.mdx"
1080
+ },
1055
1081
  {
1056
1082
  "version": "1.5.0",
1057
1083
  "file": "release-notes/1.5.0.mdx",