@iwonz/ywtc 4.1.1 → 4.1.2

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/CHANGELOG.md CHANGED
@@ -2,6 +2,24 @@
2
2
 
3
3
  Notable changes to `ywtc` are documented in this file. Versions follow [Semantic Versioning](https://semver.org/).
4
4
 
5
+ ## [4.1.2](https://github.com/iwonz/ywtc/compare/v4.1.1...v4.1.2) (2026-10-16)
6
+
7
+
8
+ ### Bug Fixes
9
+
10
+ * **confluence:** validate provider readiness responses ([1a6b32e](https://github.com/iwonz/ywtc/commit/1a6b32ed25c32bd13eca5ad78ab209e02f07ffbf))
11
+
12
+
13
+ ### Documentation
14
+
15
+ * **readme:** simplify operator documentation ([cd745e7](https://github.com/iwonz/ywtc/commit/cd745e74662cd2bd4a5edc592994e39559fab81c))
16
+
17
+
18
+ ### Maintenance
19
+
20
+ * **ci:** re-run documentation checks ([92d2504](https://github.com/iwonz/ywtc/commit/92d2504912123828429794913edc3b9703cb403e))
21
+ * **homebrew:** update formula to v4.1.1 ([6ef4a77](https://github.com/iwonz/ywtc/commit/6ef4a77b01f2730775b0e5a0ed6e22e8fe638e31))
22
+
5
23
  ## [4.1.1](https://github.com/iwonz/ywtc/compare/v4.1.0...v4.1.1) (2026-10-16)
6
24
 
7
25
 
package/README.md CHANGED
@@ -4,44 +4,24 @@
4
4
 
5
5
  # ywtc
6
6
 
7
- ## Описание
8
-
9
- `ywtc` — CLI для переноса страниц между Yandex Wiki и Confluence и экспорта в Markdown или автономный HTML. Он сохраняет структуру и содержимое, продолжает операции по state-файлу и не удаляет source или destination автоматически.
7
+ `ywtc` — CLI для переноса страниц между Yandex Wiki и Confluence и экспорта в Markdown или автономный HTML. Он сохраняет иерархию и доступное содержимое, проверяет результат, продолжает прерванные операции и ничего не удаляет автоматически.
10
8
 
11
9
  Требуются Node.js `>=24` и npm `>=11.5.1`. Лицензия — [MIT](LICENSE).
12
10
 
13
- ## Возможности
14
-
15
- | Исходный материал | Как переносится |
16
- | --- | --- |
17
- | Страницы и структура | Одна страница, полное структурное поддерево или граф связанных страниц. Иерархия восстанавливается, циклы обрабатываются без повторного переноса. Пустая страница-раздел переносится как корректная пустая страница, а не как fallback. |
18
- | Текст и оформление | Заголовки, абзацы, жирное/курсивное/зачёркнутое и цветное начертание, списки и задачи, цитаты, разделители, inline/preformatted code с языком и обычные таблицы преобразуются в нативную или семантически эквивалентную разметку destination. |
19
- | Секции и колонки | YFM `layout/block` и Confluence page layouts сохраняются нативными секциями и колонками в Yandex Wiki и Confluence. HTML использует адаптивную сетку; Markdown сохраняет все ячейки по порядку и отмечает линеаризацию как adaptation без ухудшения статуса. |
20
- | Ссылки и якоря | Ссылки между выбранными страницами переписываются на destination, якоря сохраняются. Внешние ссылки и ссылки за пределы выбранного набора остаются исходными. |
21
- | Вложения | Переносятся все доступные через API для скачивания файлы, включая PNG/JPEG/GIF/WebP/SVG, PDF, ZIP, DOC/DOCX, XLS/XLSX и PPT/PPTX. Файлы передаются потоково, совпадения имён разрешаются стабильно, размер и SHA-256 проверяются. |
22
- | Изображения | Прикреплённые изображения становятся attachments destination или локальными файлами экспорта. Внешние изображения остаются внешними; подписи и размеры сохраняются, если destination это поддерживает. |
23
- | Специальная разметка | В обе стороны сопоставляются notes ↔ `info`/`tip`/`warning`/`note`, cuts ↔ `expand`, tree ↔ `children`, задачи, code, anchors, page/attachment links и изображения. Tabs становятся статическими секциями, Grid — проверяемой статической таблицей. Такие полные эквивалентные представления считаются adaptation и остаются `complete`. Безопасный Storage Format и YFM сохраняются нативно при переносе внутри одного провайдера. |
24
- | Комментарии | По умолчанию все доступные комментарии страницы собираются в один архивный комментарий: отдельные раскрываемые ветки сохраняют участников, авторов, даты, статусы, inline-контекст, удалённые записи и вложенность ответов. Вложения, на которые есть ссылки в тексте комментариев, складываются в один проверяемый ZIP с hash-prefixed именами и manifest. Для Markdown/HTML создаются локальные секции и ZIP. |
25
- | Конструкции без точного эквивалента | Создаётся читаемый fallback и при необходимости raw snapshot. Если весь payload представлен и проверен, это adaptation со статусом `complete`; только потеря данных, значимой структуры или невозможность проверки дают degradation и `partial`. |
26
-
27
- ### Не переносится
28
-
29
- | Ограничение | Поведение ywtc |
30
- | --- | --- |
31
- | История версий | Переносится только актуальное содержимое страницы. |
32
- | Реакции и комментарии не к странице | Реакции не копируются. Комментарии к attachments, blog posts и custom content не входят в архив: читаются только footer/inline page comments. |
33
- | Пользовательские сущности, watchers, права и ограничения доступа | Не создаются; исходное авторство комментариев сохраняется в архивном тексте, а destination-объекты создаются пользователем текущего токена и наследуют права destination. |
34
- | Удалённые, недоступные или не возвращённые source API страницы | Не восстанавливаются; недоступность и пропуски фиксируются в state и отчёте. |
35
- | Точная геометрия, произвольный CSS, скрипты и неизвестные widgets/macros | Не исполняются и не подменяются недоказанным эквивалентом. Содержимое сохраняется статически, через fallback или raw snapshot; неполнота отмечается как degradation. |
36
- | Внешние файлы и изображения, не принадлежащие source | Не копируются; абсолютный URL, подпись и доступные размеры сохраняются как external reference без ухудшения статуса. Недоступный source-managed ресурс считается неполным переносом. |
37
-
38
- ## Установка
11
+ ## Быстрый старт
39
12
 
40
13
  ```bash
41
- # npm
42
14
  npm install -g @iwonz/ywtc
15
+ ywtc init --interactive
16
+ ywtc migrate --interactive
17
+ ```
18
+
19
+ Первый мастер создаёт рабочий каталог, настраивает Yandex Wiki и Confluence и проверяет соединения. Второй собирает параметры переноса и по умолчанию выполняет dry-run; live-запуск начинается только после подтверждения.
20
+
21
+ Другие способы запуска:
43
22
 
44
- # npx без глобальной установки
23
+ ```bash
24
+ # Без глобальной установки
45
25
  npx @iwonz/ywtc@latest --version
46
26
 
47
27
  # Homebrew
@@ -50,253 +30,230 @@ brew trust --tap iwonz/ywtc
50
30
  brew install ywtc
51
31
  ```
52
32
 
53
- Homebrew 7 требует доверить сторонний tap; команда `brew trust` относится только к `iwonz/ywtc`.
33
+ Обновление: `ywtc update` проверяет версию, `ywtc update --install` обновляет через обнаруженный канал, `--via npm|brew` выбирает канал явно.
34
+
35
+ ## Возможности
54
36
 
55
- Обновление:
37
+ | Материал | Результат |
38
+ | --- | --- |
39
+ | Страницы и структура | `page`, полное `subtree` или рекурсивный граф `linked`. Иерархия восстанавливается, циклы не создают повторов, пустая страница-раздел остаётся корректной пустой страницей. |
40
+ | Текст и таблицы | Сохраняются заголовки, начертания и цвет, списки и задачи, цитаты, разделители, inline/preformatted code с языком и обычные таблицы. Destination получает нативную или семантически эквивалентную разметку. |
41
+ | Секции и колонки | YFM `layout/block` и Confluence layouts преобразуются в нативные секции и колонки. HTML использует адаптивную сетку; Markdown сохраняет содержимое ячеек в исходном порядке. |
42
+ | Ссылки и якоря | Ссылки внутри выбранного набора переписываются на destination; якоря сохраняются. Внешние ссылки и переходы за границу набора остаются исходными. |
43
+ | Файлы и изображения | Доступные через API вложения передаются потоково с проверкой размера и SHA-256. Поддерживаются любые скачиваемые файлы, включая PNG/JPEG/GIF/WebP/SVG, PDF, ZIP, DOCX, XLSX и PPTX. Коллизии имён разрешаются стабильно. |
44
+ | Специальная разметка | Notes ↔ callout macros, cuts ↔ expand, tree ↔ children, задачи, code, anchors, page/attachment links и изображения получают ближайший эквивалент. Tabs становятся секциями, Grid — проверяемой статической таблицей. |
45
+ | Комментарии | По умолчанию footer/inline page comments архивируются с авторами, датами, статусами и иерархией ответов. Явно упомянутые вложения собираются в проверяемый ZIP с hash-prefixed именами и manifest. |
46
+ | Надёжность содержимого | Новая страница сразу создаётся с полным source-derived body, а не placeholder. Ошибка отдельного ресурса не блокирует текст: остаётся source-ссылка и повторяемый outcome. После записи destination перечитывается и проверяется. |
47
+ | Различия платформ | Безопасная normalization и полная adaptation считаются `complete`. Если эквивалента нет, ywtc сохраняет читаемый fallback и при необходимости raw snapshot; недоказанная полнота становится degradation. |
48
+
49
+ ### Ограничения
50
+
51
+ | Не переносится как исходная сущность | Что сохраняется |
52
+ | --- | --- |
53
+ | История версий | Текущее содержимое; последующие обновления destination образуют его обычную историю версий. |
54
+ | Реакции; комментарии к attachments, blog posts и custom content | Только footer/inline comments страницы. |
55
+ | Пользователи, watchers, права и ограничения доступа | Авторство комментариев остаётся в архивном тексте; новые объекты создаёт владелец токена и они наследуют права destination. |
56
+ | Недоступные или не возвращённые API страницы | Причина и незавершённая ветка фиксируются в state и отчёте. |
57
+ | Произвольный CSS, scripts и неизвестные интерактивные widgets/macros | Безопасное статическое представление, fallback или raw snapshot; тихой потери быть не должно. |
58
+ | Внешние файлы и изображения | Исходный абсолютный URL, alt и доступные размеры; внешние данные не скачиваются. Недоступный source-managed ресурс считается неполным переносом. |
56
59
 
57
- ```bash
58
- ywtc update # только проверка
59
- ywtc update --install # канал текущей установки
60
- ywtc update --install --via brew # явно через Homebrew
61
- ```
60
+ ## Совместимость
62
61
 
63
- ## Минимальный сценарий
62
+ | Source | Destination |
63
+ | --- | --- |
64
+ | Yandex Wiki | Confluence, Yandex Wiki, Markdown, HTML |
65
+ | Confluence | Yandex Wiki, Confluence, Markdown, HTML |
64
66
 
65
- - [ ] Установите `ywtc` одним из способов выше.
66
- - [ ] Выполните `ywtc init --interactive`.
67
- - [ ] Выполните `ywtc migrate --interactive`.
67
+ | Система | Поддерживаемый контракт | Авторизация |
68
+ | --- | --- | --- |
69
+ | Yandex Wiki | Public API v1; новые необязательные поля допускаются | OAuth или пользовательский IAM; `X-Org-Id`/`X-Cloud-Org-Id` |
70
+ | Confluence Data Center | 7.9+ без искусственной верхней границы | Bearer PAT |
71
+ | Confluence Cloud | REST v2 для страниц, REST v1 для attachments | Email + API token |
72
+
73
+ Confluence Server, Data Center Basic Auth и OAuth app-flow не поддерживаются. Перед чтением страниц и записью `doctor`/`migrate` проверяет готовность REST API: startup/maintenance HTML и неполный JSON останавливают операцию без создания state или destination-объектов. После восстановления Confluence повторите команду; если сервер исправен, проверьте `baseUrl` и `deployment`. Контрактные тесты не заменяют live-сертификацию каждой patch-версии.
68
74
 
69
75
  ## Конфигурация
70
76
 
71
- Рабочий каталог выбирается так: `--workdir` → текущий каталог с `ywtc.config.yaml` → `~/.ywtc`. Родительские каталоги не просматриваются; `migrate` автоматически создаёт отсутствующий workspace.
77
+ Рабочий каталог выбирается в порядке `--workdir` → `ywtc.config.yaml` непосредственно в текущем каталоге → `~/.ywtc`. Родительские каталоги не просматриваются.
72
78
 
73
79
  ```text
74
80
  ~/.ywtc/
75
- ├── ywtc.config.yaml # подключения, настройки и токены; mode 0600 при создании
76
- └── .states/ # state, cache и отчёты
81
+ ├── ywtc.config.yaml # подключения, настройки и токены
82
+ └── .states/ # state, cache, backups и отчёты
77
83
  ```
78
84
 
79
- `ywtc init --interactive` требует TTY, настраивает оба провайдера, скрывает токены и проверяет API и авторизацию, но не права конкретных страниц: их проверяют `doctor` и `migrate`. Для существующего workspace можно изменить профили или начать заново с backup YAML в `.states/backups/`; state сохраняется. Обычный `ywtc init` создаёт пустой шаблон. Полный пример: [`ywtc.config.example.yaml`](ywtc.config.example.yaml).
85
+ `ywtc init --interactive` настраивает и проверяет оба провайдера; `ywtc init` создаёт пустой шаблон для автоматизации. `migrate` создаёт отсутствующий workspace, но до API-запросов требует заполнить обязательные поля. Проверка мастера подтверждает API и авторизацию, но не права конкретных страниц: их проверяют `doctor` или `migrate`. Конфигурация строгая, неизвестные поля отклоняются; process environment её не переопределяет. Локальный файл игнорируется Git, новый создаётся с mode `0600`, секреты маскируются в выводе. Полный шаблон: [`ywtc.config.example.yaml`](ywtc.config.example.yaml).
80
86
 
81
- ### Поля профилей
87
+ ### Поля `ywtc.config.yaml`
82
88
 
83
- | Поле | Для кого | Обязательность / значения | Назначение |
89
+ | Поле | Профиль | Значения / default | Назначение |
84
90
  | --- | --- | --- | --- |
85
- | `defaults.timeoutMs` | файл | `1000..300000`, default `30000` | Таймаут HTTP-запроса |
86
- | `defaults.concurrency` | файл | `1..64`, default `4` | Общая параллельность операции |
87
- | `connections.<name>` | файл | минимум один; имя `[a-z0-9._-]+` | Именованное подключение |
88
- | `type` | все профили | `yandex-wiki` или `confluence` | Тип провайдера |
89
- | `token` | все профили | непустой для используемого профиля | OAuth, IAM, PAT или API token |
90
- | `apiUrl` | Yandex Wiki | URL Public API v1 | API endpoint |
91
- | `webUrl` | Yandex Wiki | URL | Базовый адрес Wiki для ссылок и выбора профиля |
92
- | `authType` | Yandex Wiki | `oauth` (default) или `iam` | Схема авторизации |
93
- | `organization.type` | Yandex Wiki | `yandex360` (default) или `cloud` | Заголовок `X-Org-Id` или `X-Cloud-Org-Id` |
94
- | `organization.id` | Yandex Wiki | непустая строка | ID организации |
95
- | `deployment` | Confluence | `data-center` или `cloud` | Тип развёртывания |
96
- | `baseUrl` | Confluence | URL | Адрес инстанса, включая context path |
97
- | `authType` | Confluence | `pat` для Data Center; `api-token` для Cloud | Схема авторизации |
98
- | `email` | Confluence Cloud | непустой для используемого профиля | Email Atlassian-аккаунта |
99
- | `limits.readConcurrency` | все профили | `1..64`, default `4` | Параллельные чтения |
100
- | `limits.writeConcurrency` | все профили | `1..32`, default `2` | Параллельные записи |
101
- | `limits.downloadConcurrency` | все профили | `1..32`, default `2` | Параллельные скачивания |
102
- | `limits.uploadConcurrency` | все профили | `1..32`, default `2` | Параллельные загрузки |
103
- | `limits.requestsPerSecond` | все профили | `1..1000`, default `8` | Средняя частота запросов |
104
- | `limits.burst` | все профили | `1..1000`, default `8` | Допустимый кратковременный burst |
105
-
106
- Конфигурация строгая: неизвестные поля считаются ошибкой. Все значения, включая токены, email, таймауты и лимиты, читаются только из `ywtc.config.yaml`; process environment их не переопределяет. Файл рабочего каталога игнорируется Git, а токены маскируются в диагностике и отчётах.
107
-
108
- ## Направления и совместимость
109
-
110
- | Source | Destination | Поддержка |
111
- | --- | --- | --- |
112
- | Yandex Wiki | Confluence | Да |
113
- | Yandex Wiki | Yandex Wiki | Да, включая другой профиль или инстанс |
114
- | Confluence | Yandex Wiki | Да |
115
- | Confluence | Confluence | Да, включая другой профиль или инстанс |
116
- | Yandex Wiki или Confluence | Markdown | Да |
117
- | Yandex Wiki или Confluence | статический HTML | Да |
118
-
119
- | Система | Контракт | Авторизация |
120
- | --- | --- | --- |
121
- | Yandex Wiki | Public API v1; новые необязательные поля принимаются | OAuth или пользовательский IAM; `X-Org-Id`/`X-Cloud-Org-Id` |
122
- | Confluence Data Center | 7.9+ без верхней границы; capabilities проверяются до записи | Bearer PAT |
123
- | Confluence Cloud | REST v2 для страниц и REST v1 для attachments | Email + API token |
124
-
125
- Confluence Server, Data Center Basic Auth и OAuth app-flow не поддерживаются. Совместимость определяется preflight-проверкой необходимых API/capabilities, а не сертификацией каждой patch-версии.
126
-
127
- ## Как получить токены
128
-
129
- ### Yandex Wiki
130
-
131
- - [ ] Создайте приложение в [Яндекс OAuth](https://oauth.yandex.ru/).
132
- - [ ] Выдайте права Wiki на чтение; для destination также нужны права записи.
133
- - [ ] Получите OAuth-токен пользователя с доступом к страницам. Для федеративного пользователя Yandex Cloud допустим IAM-токен и `authType: iam`.
134
- - [ ] Найдите ID организации в **Yandex Tracker → Администрирование → Организации**.
135
- - [ ] Укажите `organization.type: yandex360` для Яндекс 360 или `cloud` для Cloud Organization.
136
- - [ ] Запишите токен в `connections.<name>.token` выбранного профиля.
137
-
138
- ### Confluence Data Center
139
-
140
- - [ ] Откройте **Avatar → Settings → Personal access tokens → Create token**.
141
- - [ ] Создайте PAT и запишите его в `connections.<name>.token`.
142
- - [ ] Используйте `deployment: data-center` и `authType: pat`.
143
- - [ ] Проверьте права на чтение source и создание/изменение страниц и вложений destination.
144
-
145
- ### Confluence Cloud
146
-
147
- - [ ] Создайте [Atlassian API token](https://id.atlassian.com/manage-profile/security/api-tokens).
148
- - [ ] Используйте `deployment: cloud`, `authType: api-token`, `token` и `email`.
149
- - [ ] Запишите API token и email аккаунта непосредственно в выбранный профиль.
150
- - [ ] Проверьте доступ аккаунта к source и destination spaces.
151
-
152
- ## Параметры
91
+ | `defaults.timeoutMs` | общий | `1000..300000`; `30000` | Таймаут HTTP-запроса |
92
+ | `defaults.concurrency` | общий | `1..64`; `4` | Общая параллельность операции |
93
+ | `connections.<name>` | общий | имя `[a-z0-9._-]+` | Именованное подключение |
94
+ | `type` | любой | `yandex-wiki` или `confluence` | Провайдер |
95
+ | `token` | любой | непустой | OAuth, IAM, PAT или API token |
96
+ | `apiUrl` / `webUrl` | Yandex Wiki | URL API v1 / базовый web URL | API-запросы, ссылки и выбор профиля |
97
+ | `authType` | Yandex Wiki | `oauth` или `iam`; `oauth` | Схема авторизации; IAM допустим только с Cloud Organization |
98
+ | `organization.type` | Yandex Wiki | `yandex360` или `cloud`; `yandex360` | Выбирает `X-Org-Id` или `X-Cloud-Org-Id` |
99
+ | `organization.id` | Yandex Wiki | непустой | ID организации |
100
+ | `deployment` | Confluence | `data-center` или `cloud` | Тип инстанса |
101
+ | `baseUrl` | Confluence | URL, включая context path | Базовый адрес API и web |
102
+ | `authType` | Confluence | `pat` или `api-token` | PAT для Data Center; API token для Cloud |
103
+ | `email` | Confluence Cloud | непустой | Atlassian account email для Basic Auth |
104
+ | `limits.readConcurrency` | любой | `1..64`; `4` | Параллельные чтения |
105
+ | `limits.writeConcurrency` | любой | `1..32`; `2` | Параллельные записи |
106
+ | `limits.downloadConcurrency` / `uploadConcurrency` | любой | `1..32`; `2` | Параллельные передачи файлов |
107
+ | `limits.requestsPerSecond` | любой | `1..1000`; `8` | Устойчивая частота запросов |
108
+ | `limits.burst` | любой | `1..1000`; Yandex `8`, Confluence `10` | Кратковременный burst |
109
+
110
+ ### Токены
111
+
112
+ #### Yandex Wiki
113
+
114
+ 1. Создайте приложение в [Яндекс OAuth](https://oauth.yandex.ru/) и выдайте ему [права Wiki](https://yandex.ru/support/wiki/ru/api-ref/access) на чтение, а для destination — на запись.
115
+ 2. Получите OAuth-токен пользователя с доступом к нужным страницам. Для федеративного пользователя Yandex Cloud допустим IAM-токен.
116
+ 3. Найдите ID в **Yandex Tracker → Администрирование → Организации** и выберите `organization.type: yandex360` либо `cloud`.
117
+ 4. Запишите значения в Yandex-профиль; для IAM используйте `authType: iam` и Cloud Organization.
118
+
119
+ #### Confluence Data Center
120
+
121
+ 1. Откройте **Avatar → Settings → Personal access tokens → Create token**; порядок действий описан в [документации Atlassian](https://confluence.atlassian.com/enterprise/using-personal-access-tokens-1026032365.html).
122
+ 2. Запишите PAT в профиль с `deployment: data-center` и `authType: pat`.
123
+ 3. Убедитесь, что пользователь может читать source и создавать страницы и attachments в destination.
124
+
125
+ #### Confluence Cloud
126
+
127
+ 1. Создайте [Atlassian API token](https://id.atlassian.com/manage-profile/security/api-tokens).
128
+ 2. Используйте `deployment: cloud`, `authType: api-token`, `email` и `token`; аккаунту нужен доступ к исходному и целевому spaces.
129
+
130
+ ## CLI
153
131
 
154
132
  ### Команды
155
133
 
156
134
  | Команда | Назначение |
157
135
  | --- | --- |
158
- | `ywtc init [--workdir <path>] [--interactive]` | Создать шаблон либо настроить и проверить подключения в TTY wizard |
159
- | `ywtc doctor [options]` | Проверить workspace; с source и destination выполнить read-only preflight |
160
- | `ywtc migrate --interactive` | Выбрать параметры, выполнить dry-run и явно продолжить live-перенос в TTY wizard |
161
- | `ywtc migrate --source <locator> --destination <locator\|directory> [options]` | Неинтерактивно перенести или экспортировать выбранный граф страниц |
162
- | `ywtc reports list [--workdir <path>]` | Показать локальные отчёты от новых к старым |
163
- | `ywtc reports open [run-id\|last] [--workdir <path>]` | Открыть выбранный отчёт; `last` или отсутствие аргумента открывает последний корректный |
164
- | `ywtc update [--install] [--via npm\|brew]` | Проверить или установить обновление безопасным для текущего канала способом |
165
- | `ywtc --help`, `ywtc <command> --help` | Показать общую или командную справку |
166
- | `ywtc --version` | Показать версию |
136
+ | `ywtc init [-i] [-w <path>]` | Создать workspace или настроить оба подключения в TTY-мастере |
137
+ | `ywtc doctor [options]` | Проверить workspace; с source и destination — выполнить read-only preflight |
138
+ | `ywtc migrate -i` | Выбрать параметры, выполнить dry-run и при допустимом результате явно перейти к live |
139
+ | `ywtc migrate -s <locator> -d <locator\|directory> [options]` | Неинтерактивный перенос или экспорт |
140
+ | `ywtc reports list [-w <path>]` | Показать локальные отчёты от новых к старым |
141
+ | `ywtc reports open [run-id\|last] [-w <path>]` | Открыть выбранный или последний корректный отчёт |
142
+ | `ywtc update [-i] [-c npm\|brew]` | Проверить или установить обновление безопасным для текущего канала способом |
167
143
 
168
144
  ### Опции
169
145
 
170
- | Полная опция | Short | Команды | Обязательность / значения | Назначение |
171
- | --- | --- | --- | --- | --- |
172
- | `--interactive` | `-i` | `init`, `migrate` | требует stdin/stdout TTY | Запустить обязательный мастер настройки или миграции |
173
- | `--workdir <path>` | `-w` | `init`, `doctor`, `migrate`, `reports` | config в CWD или `~/.ywtc` | Явно выбрать workspace; поддерживается `~/...` |
174
- | `--source <value>` | `-s` | `doctor`, `migrate` | обязательно для неинтерактивного `migrate`; в `doctor` вместе с destination | URL, page ID или Yandex slug |
175
- | `--destination <value>` | `-d` | `doctor`, `migrate` | обязательно для неинтерактивного `migrate`; в `doctor` вместе с source | Родительская страница или каталог экспорта |
176
- | `--source-profile <name>` | `-S` | `doctor`, `migrate` | при неоднозначном коротком locator | Профиль source из `connections` |
177
- | `--destination-profile <name>` | `-D` | `doctor`, `migrate` | при неоднозначном remote locator | Профиль destination; несовместим с файловым экспортом |
178
- | `--scope <mode>` | `-m` | `doctor`, `migrate` | `page`, `subtree` (default), `linked` | Граница выбора страниц |
179
- | `--source-status <status>` | `-t` | `doctor`, `migrate` | `all` (default) или `current` | Статус автоматически обнаруживаемых страниц; явно заданный root включается всегда |
180
- | `--comments` / `--no-comments` | `-C` / `-N` | `doctor`, `migrate` | комментарии включены по умолчанию | Архивировать page comments или полностью отключить их чтение и запись |
181
- | `--format <format>` | `-f` | `doctor`, `migrate` | `markdown` или `html` | Делает destination файловым каталогом |
182
- | `--archive` | `-a` | `migrate` | только с файловым destination | Дополнительно создать ZIP рядом с каталогом |
183
- | `--dry-run` | `-n` | `migrate` | default `false`; default-действие wizard | Discovery и план без записи в destination |
184
- | `--fresh` | `-F` | `migrate` | default `false` | Игнорировать mappings текущего state |
185
- | `--open-report` | `-o` | `migrate` | default `false` | Открыть итоговый HTML-отчёт; ошибка браузера не меняет результат миграции |
186
- | `--concurrency <n>` | `-j` | `migrate` | `1..64`; иначе config default | Общая параллельность; профильные лимиты сохраняются |
187
- | `--state <path>` | `-r` | `migrate` | внутри workspace | Явный state вместо автоматического |
188
- | `--install` | `-i` | `update` | default `false` | Установить найденное обновление |
189
- | `--via <channel>` | `-c` | `update` | `npm` или `brew` | Явно выбрать совместимый канал обновления |
190
- | `--help` | `-h` | CLI и команды | необязательно | Справка |
191
- | `--version` | `-v` | CLI | необязательно | Версия |
192
-
193
- Одинаковые short-алиасы относятся только к своей команде: например, `migrate -i` запускает wizard, а `update -i` устанавливает обновление. В интерактивном режиме переданные опции становятся редактируемыми начальными значениями; без него `source` и `destination` обязательны.
194
-
195
- ### Локаторы
196
-
197
- - Yandex Wiki: полный URL, числовой page ID или slug, например `team/start`.
198
- - Confluence: числовой page ID, URL с `pageId=<id>` либо URL с `/pages/<id>` или `/content/<id>`.
199
- - Полный URL автоматически выбирает профиль по нормализованному base URL.
200
- - Короткий ID/slug выбирается автоматически только при единственном подходящем профиле; иначе нужен `--source-profile` или `--destination-profile`.
201
- - Каталог является файловой destination только вместе с `--format`.
202
-
203
- ### Scope
204
-
205
- - `page` — только исходная страница.
206
- - `subtree` — страница и все доступные структурные потомки до последнего уровня; default. С `all` Yandex Wiki включает `actual` и `obsolete`, а с `current` — только `actual`. Confluence переносит страницы, доступные через hierarchy API; archived, trashed и historical versions могут не возвращаться этим API.
207
- - `linked` — детерминированный BFS по внутренним ссылкам и page/include references до фиксированной точки. Циклы завершаются безопасно, каждая страница обрабатывается один раз; внешние и недоступные ссылки не обходятся и попадают в отчёт.
208
-
209
- ## Частые примеры
146
+ | Полная / short | Команды | Значения и назначение |
147
+ | --- | --- | --- |
148
+ | `--interactive`, `-i` | `init`, `migrate` | TTY-мастер; в `migrate` переданные опции становятся редактируемыми defaults |
149
+ | `--workdir`, `-w` | `init`, `doctor`, `migrate`, `reports` | Явный workspace; поддерживается `~/...` |
150
+ | `--source`, `-s` | `doctor`, `migrate` | URL, page ID или Yandex slug; обязателен в неинтерактивном `migrate` |
151
+ | `--destination`, `-d` | `doctor`, `migrate` | Родительская страница или каталог; обязателен в неинтерактивном `migrate` |
152
+ | `--source-profile`, `-S` | `doctor`, `migrate` | Имя source-профиля при неоднозначном коротком locator |
153
+ | `--destination-profile`, `-D` | `doctor`, `migrate` | Имя remote destination-профиля; запрещён для файлового экспорта |
154
+ | `--scope`, `-m` | `doctor`, `migrate` | `page`, `subtree` (default), `linked` |
155
+ | `--source-status`, `-t` | `doctor`, `migrate` | `all` (default) или `current`; root включается всегда |
156
+ | `--comments`, `-C` / `--no-comments`, `-N` | `doctor`, `migrate` | Комментарии включены по умолчанию; `-N` исключает все comment API calls |
157
+ | `--format`, `-f` | `doctor`, `migrate` | `markdown` или `html`; делает destination файловым |
158
+ | `--archive`, `-a` | `migrate` | Дополнительный ZIP для файлового экспорта |
159
+ | `--dry-run`, `-n` | `migrate` | Полный discovery/render без destination writes |
160
+ | `--fresh`, `-F` | `migrate` | Игнорировать mappings; существующий live-state сохранить как backup |
161
+ | `--open-report`, `-o` | `migrate` | Открыть итоговый HTML; ошибка opener не меняет outcome переноса |
162
+ | `--concurrency`, `-j` | `migrate` | `1..64`; иначе `defaults.concurrency` |
163
+ | `--state`, `-r` | `migrate` | Явный state path внутри workspace |
164
+ | `--install`, `-i` | `update` | Установить найденное обновление |
165
+ | `--via`, `-c` | `update` | `npm` или `brew` |
166
+ | `--help`, `-h` / `--version`, `-v` | CLI | Справка / версия |
167
+
168
+ Short-алиасы локальны для команды: `migrate -i` запускает мастер, `update -i` устанавливает обновление.
169
+
170
+ ### Locators и выбор страниц
171
+
172
+ - Yandex Wiki: полный URL, числовой page ID или slug вида `team/start`.
173
+ - Confluence: числовой page ID, URL с `pageId=<id>`, `/pages/<id>` или `/content/<id>`.
174
+ - Полный URL выбирает профиль по нормализованному base URL. Для неоднозначного ID/slug укажите профиль явно.
175
+ - Каталог считается destination только с `--format`.
176
+
177
+ | Scope | Выбор |
178
+ | --- | --- |
179
+ | `page` | Только root |
180
+ | `subtree` | Root и все доступные структурные descendants до последнего уровня; default |
181
+ | `linked` | Детерминированный BFS по внутренним ссылкам и page/include references; циклы завершаются безопасно |
182
+
183
+ `--source-status all` включает все доступные descendants: в Yandex Wiki — `actual` и `obsolete`; `current` оставляет только `actual/current`. Confluence зависит от hierarchy API и может не возвращать archived, trashed и historical versions.
184
+
185
+ ### Примеры
210
186
 
211
187
  ```bash
212
- # Перенести всё структурное поддерево
213
- ywtc migrate --source https://wiki.example.com/team/start \
214
- --destination https://confluence.example.com/confluence/pages/viewpage.action?pageId=123
188
+ # Перенести структурное поддерево
189
+ ywtc migrate -s https://wiki.example.com/team/start \
190
+ -d https://confluence.example.com/confluence/pages/viewpage.action?pageId=123
215
191
 
216
- # Перенести граф рекурсивно связанных страниц
217
- ywtc migrate --source https://wiki.example.com/team/start \
218
- --destination https://confluence.example.com/confluence/pages/viewpage.action?pageId=123 \
219
- --scope linked
192
+ # Перенести рекурсивно связанные страницы
193
+ ywtc migrate -s https://wiki.example.com/team/start \
194
+ -d https://confluence.example.com/confluence/pages/viewpage.action?pageId=123 \
195
+ -m linked
220
196
 
221
- # Создать автономный HTML-экспорт и ZIP
222
- ywtc migrate --source https://wiki.example.com/team/start \
223
- --destination ./exports/knowledge-base \
224
- --format html --archive
197
+ # Создать автономный HTML и ZIP
198
+ ywtc migrate -s https://wiki.example.com/team/start \
199
+ -d ./exports/knowledge-base -f html -a
225
200
 
226
201
  # Открыть последний корректный отчёт
227
202
  ywtc reports open last
228
203
  ```
229
204
 
230
- `doctor` без endpoints проверяет workspace и конфигурацию, а с source и destination выполняет page-specific read-only capability-preflight.
231
-
232
205
  ## Файловый экспорт
233
206
 
234
- Markdown создаёт `index.md`, `pages/`, `attachments/`, `.ywtc-export.json` и, при деградациях, `_source/`. HTML создаёт автономный адаптивный сайт с локальным `assets/site.css`; он работает через `file://` и на static hosting без CDN или внешнего runtime.
235
-
236
- При включённых комментариях каждая страница получает секцию `Комментарии` с раскрываемыми ветками. Связанные из комментариев файлы находятся в одном ZIP рядом с attachments страницы; `manifest.json` внутри ZIP связывает source comment ID, исходную ссылку, исходное и архивное имя, размер и SHA-256.
237
-
238
- Экспорт сначала строится в staging-каталоге. Существующий каталог заменяется только при строгом актуальном manifest с `tool: ywtc` и той же canonical identity, а прежний каталог сохраняется как timestamped backup. `--archive` оставляет каталог и создаёт новый ZIP, не перезаписывая существующий архив.
239
-
240
- ## State
207
+ Markdown создаёт `index.md`, `pages/`, `attachments/` и `.ywtc-export.json`. HTML создаёт автономный адаптивный сайт с локальным CSS, который работает через `file://` и на static hosting без CDN или внешнего runtime. `_source/` появляется только для страниц, которым нужен raw snapshot.
241
208
 
242
- State хранится в `<workdir>/.states/<automatic-id>.json`. ID строится из канонических профилей и ID source/destination, для экспорта — также из формата; форма locator, `scope` и `source-status` его не меняют. Относительный `--state` остаётся внутри workspace. Live-run блокирует state от параллельной записи; подтверждённо stale lock восстанавливается.
209
+ Внутренние ссылки и resources становятся относительными. Комментарии входят в страницу раскрываемыми ветками; явно связанные с ними файлы находятся в одном ZIP с `manifest.json`.
243
210
 
244
- ### Повторные запуски
211
+ Экспорт строится в соседнем staging-каталоге. Существующий каталог заменяется только при актуальном manifest с `tool: ywtc` и той же canonical identity; предыдущая версия сохраняется как timestamped backup. `--archive` оставляет каталог и создаёт новый ZIP, не перезаписывая существующий.
245
212
 
246
- - Одинаковые source и destination автоматически подхватывают один state независимо от формы URL/ID/slug.
247
- - Переключение `current → all` расширяет тот же state новыми страницами без дубликатов; обратное переключение не удаляет mappings вне текущего выбора.
248
- - Подтверждённая state-mapping означает, что source авторитетен: отличающийся body, title или parent mapped-страницы обновляется поверх актуальной destination-версии, а прежнее содержимое остаётся в истории провайдера.
249
- - Неверный parent исправляется до потомков. Временный `404` повторяется с backoff; устойчиво пропавшая mapping восстанавливается под ожидаемым родителем с сохранением прежнего ID.
250
- - Страницы и файлы сверяются по ID, размеру и SHA-256. Cache переиспользуется; неудачные вложения получают стабильные уникальные имена и повторяются без `--fresh`.
251
- - Прежний неизменённый placeholder заменяется source-derived контентом. Ошибка файла оставляет полный текст и source-ссылку, даёт `partial` и повторяется позже.
252
- - Архивы комментариев и ZIP проверяются и переиспользуются. Confluence-архив обновляется версией, Yandex Wiki получает новую ревизию; удалённый mapped-комментарий создаётся заново, исчезнувший source-архив помечается `stale`.
253
- - Запуск с `--no-comments` не обращается к comment API и не удаляет ранее созданные архивы; следующий обычный запуск дополнит тот же state.
254
- - `conflict` используется только при доказанной неоднозначности immutable ownership/identity: несколько source mappings на один destination ID, несовпадение возвращённого immutable ID или несколько равноправных ownership-кандидатов. Версия, title, URL, slug, parent, fingerprint, HTTP `409`, слово `conflict` в сообщении и коллизия имени сами по себе конфликтом не являются.
255
- - `--fresh` игнорирует mappings; перед live-run прежний state сохраняется как backup, а destination может получить новые объекты.
256
- - Удалённые из source объекты автоматически не удаляются из destination.
213
+ ## State и повторные запуски
257
214
 
258
- При SIGINT/SIGTERM новые задачи не ставятся, активные безопасные операции завершаются, state и отчёт сохраняются. Коды выхода: `0` — completed; `1` — partial или verification failure; `2` — usage/config/preflight; `130`/`143` — остановка сигналом.
215
+ State находится в `<workdir>/.states/<automatic-id>.json`. ID зависит от канонических профилей и page IDs, а для экспорта — ещё от формата; URL/ID/slug, `scope` и `source-status` его не меняют. Относительный `--state` разрешается только внутри workspace.
259
216
 
260
- ## Отчёты
217
+ - Повтор одинакового направления подхватывает mappings, cache и незавершённые операции без дубликатов.
218
+ - Для доказанной mapping source авторитетен: body, title и parent обновляются поверх текущей destination-версии, а прежнее содержимое остаётся в истории. Unmapped и неоднозначно принадлежащие объекты не перезаписываются.
219
+ - Неверная иерархия исправляется сверху вниз; временные `404` повторяются, пропавшая mapped-страница восстанавливается под ожидаемым родителем без удаления старого объекта.
220
+ - Файлы согласуются по immutable ID, размеру и SHA-256; проверенный cache переиспользуется, занятые имена получают стабильный суффикс.
221
+ - Комментарии и их ZIP проверяются и переиспользуются. Confluence-архив обновляется версией, Yandex Wiki получает новую ревизию; исчезнувший source-архив сохраняется как stale.
222
+ - `current → all` расширяет тот же state; обратное переключение не удаляет прежние mappings. Удаление в source также не удаляет destination.
223
+ - `--fresh` игнорирует mappings и сохраняет прежний state как backup; destination при этом может получить новые объекты.
261
224
 
262
- Каждый запуск создаёт `<workdir>/.states/reports/<run-id>/index.html` и очищенный `report.json`, затем печатает run ID, `file://` URL и команду повторного открытия. `--open-report` открывает отчёт сразу; `ywtc reports list` показывает историю, `ywtc reports open <run-id>` — выбранный запуск, а `ywtc reports open last` или `ywtc reports open` — последний корректный.
225
+ Live-run использует exclusive lock; stale lock восстанавливается. При SIGINT/SIGTERM новые задачи не запускаются, безопасные активные операции завершаются, state и отчёт сохраняются. Коды выхода: `0` — completed, `1` — partial/verification failure, `2` — usage/config/preflight, `130`/`143` — сигнал.
263
226
 
264
- Автономный HTML-отчёт работает без сети. Плоская сводка показывает статус, время, ненулевые показатели source/destination и metadata в порядке `RUN ID`, `STATE`, `SOURCE`, `DESTINATION`; source и destination открываются по безопасным ссылкам. `report.json` доступен для скачивания. Нулевые необязательные показатели и пустые категории скрываются.
227
+ ## Отчёты и статусы
265
228
 
266
- Ниже находится раскрытое дерево исходной иерархии, включая исключённые страницы; доступны поиск, фильтры проблем и прямые ссылки на source/destination. Строка страницы открывает только доступные вкладки файлов, комментариев, сравнения и проблем. Ошибки и зависимые `blocked` объекты подсвечиваются в дереве и объясняются в деталях. RU/EN и system/light/dark переключаются иконками; выбор сохраняется локально. Интерфейс адаптирован для мобильного экрана.
229
+ Каждый запуск создаёт `<workdir>/.states/reports/<run-id>/index.html` и очищенный `report.json`, затем печатает URL и команду открытия. Используйте `--open-report`, `ywtc reports list` или `ywtc reports open [run-id|last]`; без selector `open` также выбирает последний корректный отчёт.
267
230
 
268
- HTML/JSON, итог терминала и `reports list` используют одинаковые счётчики. Известный source volume отделён от подтверждённых transferred bytes; неизвестные размеры отмечены явно. `report.json` не содержит содержимое страниц, тексты комментариев или preview HTML — они остаются только в локальном `index.html`.
231
+ Автономный отчёт показывает только ненулевые показатели, канонические source/destination, исходную иерархию, исключённые страницы и проблемы. Дерево поддерживает поиск и фильтры; детали страницы содержат доступные files, comments, side-by-side comparison и диагностику. RU/EN и system/light/dark переключаются иконками. `report.json` не содержит body страниц, тексты комментариев или preview HTML.
269
232
 
270
- Качество преобразования учитывается отдельно: normalization — безопасная разница сериализации; adaptation — полное эквивалентное представление, например Grid → static table или колонки другой ширины; degradation — доказанная неполнота, влияющая на `partial`; preserved external reference — исходный внешний URL, который и должен остаться внешним. Normalization и adaptation не увеличивают warnings и не переводят запуск в `completed-with-warnings`.
233
+ ### Outcomes объектов
271
234
 
272
- ### Статусы переноса
273
-
274
- Статусы страниц:
275
-
276
- | Статус | Смысл | Данные записаны | Что делать |
277
- |---|---|---:|---|
278
- | `complete` | Страница и связанные объекты записаны и проверены | Да | Ничего |
279
- | `partial` | Часть данных, managed-ресурсов, комментариев или значимой структуры отсутствует либо результат не проверен | Да | Посмотреть degradation в отчёте; повторить запуск для retryable-проблем |
280
- | `failed` | Операция страницы началась, но корректная запись или проверка не удалась | Возможно частично | Исправить root error и повторить ту же миграцию |
281
- | `blocked` | Страница не запускалась из-за недоступного failed/conflict родителя или другой зависимости | Нет в этом запуске | Исправить указанную upstream-ошибку и повторить запуск |
282
- | `conflict` | Immutable ownership/identity destination доказанно неоднозначна, в отчёте перечислены кандидаты | Нет автоматической перезаписи | Проверить candidate IDs и устранить неоднозначное сопоставление |
283
- | `planned` | Объект рассчитан в `--dry-run`; запись не выполнялась | Нет | Убрать `--dry-run` для переноса |
284
- | `not-started` | Live-run остановился до начала независимой операции | Нет | Повторить ту же миграцию |
285
-
286
- Статусы файлов:
235
+ | Outcome | Объекты | Значение и действие |
236
+ | --- | --- | --- |
237
+ | `complete` | страницы, файлы, comment archives | Записано и проверено; действий не требуется |
238
+ | `partial` | страницы, файлы, comment archives | Основное представление доступно, но часть данных отсутствует или не проверена; изучить degradation и повторить retryable-операцию |
239
+ | `failed` | все | Операция началась, но корректная запись или проверка не получилась; исправить root error и повторить запуск |
240
+ | `blocked` | страницы, файлы, comment archives | Операция не начиналась из-за недоступного parent/dependency; сначала исправить upstream failure/conflict |
241
+ | `conflict` | mapped-объекты | Immutable ownership/identity неоднозначна; проверить candidate IDs. Обычная новая версия, ручное изменение, title collision или HTTP `409` конфликтом не считаются |
242
+ | `planned` | все | Объект рассчитан в dry-run, записи не было; запустить live |
243
+ | `not-started` | все | Live-run остановился до независимой операции; повторить запуск |
287
244
 
288
- | Статус | Смысл | Данные записаны | Что делать |
289
- |---|---|---:|---|
290
- | `complete` | Файл загружен и проверен | Да | Ничего |
291
- | `partial` | Файл доступен через сохранённый fallback, но нативная передача неполна | Частично | Проверить fallback и повторить retryable-операцию |
292
- | `failed` | Download, upload или verification файла выполнялся и завершился ошибкой | Возможно частично | Проверить причину и повторить запуск |
293
- | `blocked` | Файл не обрабатывался, потому что destination-страница недоступна | Нет в этом запуске | Сначала устранить указанную ошибку страницы |
294
- | `planned` | Файл только запланирован в `--dry-run` | Нет | Запустить без `--dry-run` |
295
- | `not-started` | Live-run прерван до начала обработки файла | Нет | Повторить ту же миграцию |
245
+ ### Качество преобразования
296
246
 
297
- `failed` означает неудавшуюся попытку самого объекта; `blocked` — сознательно не начатую операцию из-за upstream-зависимости. Поэтому зависимые блокировки показываются отдельно и не увеличивают число root errors.
247
+ | Категория | Влияние |
248
+ | --- | --- |
249
+ | Normalization | Безопасная разница сериализации или нативный эквивалент; остаётся `complete` |
250
+ | Adaptation | Другое представление с проверенной полнотой, например Grid → static table; остаётся `complete` |
251
+ | Preserved external reference | Внешний URL сохранён как внешний и не требует копирования; остаётся `complete` |
252
+ | Degradation | Данные или значимая структура отсутствуют либо полнота не доказана; даёт `partial` |
253
+ | Warning | Требует внимания, но сам по себе не доказывает потерю |
254
+ | Error | Неудавшаяся API/record/verification операция; итог зависит от сохранности полного body и объекта |
298
255
 
299
- Итоговый статус запуска: `completed`, `completed-with-warnings`, `partial`, `failed`, `cancelled` или `interrupted`. Provider-aware verification допускает безопасные различия сериализации и полные adaptations. Только потеря текста, ссылки, ячейки таблицы, кода, managed-изображения, вложения, комментария, anchor или невозможность доказать полноту ухудшает статус. Технический статус `skeleton-created` уже содержит source-derived bootstrap, а не progress-placeholder.
256
+ Итог запуска: `completed`, `completed-with-warnings`, `partial`, `failed`, `cancelled` или `interrupted`. HTML, JSON, terminal summary и `reports list` используют одинаковые totals; зависимые `blocked` объекты не считаются отдельными root errors.
300
257
 
301
258
  ## Разработка
302
259
 
@@ -308,6 +265,6 @@ npm run workspace:init
308
265
  npm run check
309
266
  ```
310
267
 
311
- `npm run check` запускает проверку репозитория и секретов, production audit уровня high/critical, TypeScript, Biome, Knip, тесты, сборку, проверку npm-пакета и строгую OpenSpec-валидацию. Любое изменение проходит полный OpenSpec-цикл из [`AGENTS.md`](AGENTS.md).
268
+ `npm run check` запускает release hygiene и security audit, TypeScript, Biome, Knip, Vitest, Playwright, сборку, package smoke-test и строгую OpenSpec-валидацию. Любое изменение проходит цикл из [`AGENTS.md`](AGENTS.md).
312
269
 
313
- Release Please рассчитывает SemVer из Conventional Commits. После merge release PR GitHub Actions проверяет релиз, публикует GitHub Release и npm-пакет через OIDC provenance, затем обновляет и проверяет Homebrew-формулу. Версии и changelog вручную не изменяются.
270
+ Release Please рассчитывает SemVer из Conventional Commits. После merge release PR GitHub Actions публикует GitHub Release и npm-пакет с OIDC provenance, затем генерирует, устанавливает и тестирует Homebrew-формулу.