@iwonz/ywtc 4.1.0 → 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 +30 -0
- package/README.md +189 -244
- package/dist/clients/confluence-cloud.js +45 -38
- package/dist/clients/confluence-cloud.js.map +1 -1
- package/dist/clients/confluence-response.d.ts +226 -0
- package/dist/clients/confluence-response.js +205 -0
- package/dist/clients/confluence-response.js.map +1 -0
- package/dist/clients/confluence.js +51 -40
- package/dist/clients/confluence.js.map +1 -1
- package/dist/connection-verifier.js +6 -1
- package/dist/connection-verifier.js.map +1 -1
- package/dist/doctor.js +3 -1
- package/dist/doctor.js.map +1 -1
- package/dist/http.js +28 -2
- package/dist/http.js.map +1 -1
- package/dist/migrator.js +4 -2
- package/dist/migrator.js.map +1 -1
- package/dist/report-ui/index.html +7 -7
- package/docs/assets/readme-header.png +0 -0
- package/docs/assets/report-header-transparent.png +0 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -4,48 +4,24 @@
|
|
|
4
4
|
|
|
5
5
|
# ywtc
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
`ywtc` — CLI для переноса страниц между Yandex Wiki и Confluence и экспорта в Markdown или автономный HTML. Утилита сохраняет структуру, ссылки и вложения, явно отмечает деградации и продолжает прерванные операции по state-файлу. Исходные данные и страницы назначения автоматически не удаляются.
|
|
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
|
-
| Реакции на комментарии | Не копируются и не влияют на список участников архива. |
|
|
33
|
-
| Комментарии непосредственно к attachments, blog posts и custom content | Не входят в архив страницы; читаются только footer/inline page comments. |
|
|
34
|
-
| Пользовательские сущности, watchers, права и ограничения доступа | Не создаются; исходное авторство комментариев сохраняется в архивном тексте, а destination-объекты создаются пользователем текущего токена и наследуют права destination. |
|
|
35
|
-
| Удалённые, недоступные или не возвращённые source API страницы | Не восстанавливаются; недоступность и пропуски фиксируются в state и отчёте. |
|
|
36
|
-
| Точная пиксельная геометрия, произвольный CSS и активные скрипты | Не исполняются и не обещают визуальную идентичность. Содержимое и поддерживаемая структура сохраняются нативно или статически; неподдерживаемая часть получает читаемый fallback и raw snapshot. |
|
|
37
|
-
| Сторонние и неизвестные macros/виджеты | Не подменяются приблизительным macro без доказанного эквивалента: сохраняются безопасным статическим представлением и raw snapshot с явной degradation. |
|
|
38
|
-
| Внешние файлы и изображения, не принадлежащие source | Не копируются; абсолютный URL, подпись и доступные размеры сохраняются как external reference без ухудшения статуса. Недоступный source-managed ресурс считается неполным переносом. |
|
|
39
|
-
| Активные скрипты, iframe, формы и интерактивное поведение embed-объектов | Не исполняются в destination; вместо них сохраняется безопасное статическое представление или raw snapshot. |
|
|
40
|
-
| Пиксельная идентичность и поведение vendor-specific элементов без эквивалента | Используется ближайшее семантическое представление; различия явно отмечаются в отчёте. |
|
|
41
|
-
|
|
42
|
-
## Установка
|
|
11
|
+
## Быстрый старт
|
|
43
12
|
|
|
44
13
|
```bash
|
|
45
|
-
# npm
|
|
46
14
|
npm install -g @iwonz/ywtc
|
|
15
|
+
ywtc init --interactive
|
|
16
|
+
ywtc migrate --interactive
|
|
17
|
+
```
|
|
47
18
|
|
|
48
|
-
|
|
19
|
+
Первый мастер создаёт рабочий каталог, настраивает Yandex Wiki и Confluence и проверяет соединения. Второй собирает параметры переноса и по умолчанию выполняет dry-run; live-запуск начинается только после подтверждения.
|
|
20
|
+
|
|
21
|
+
Другие способы запуска:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
# Без глобальной установки
|
|
49
25
|
npx @iwonz/ywtc@latest --version
|
|
50
26
|
|
|
51
27
|
# Homebrew
|
|
@@ -54,261 +30,230 @@ brew trust --tap iwonz/ywtc
|
|
|
54
30
|
brew install ywtc
|
|
55
31
|
```
|
|
56
32
|
|
|
57
|
-
|
|
33
|
+
Обновление: `ywtc update` проверяет версию, `ywtc update --install` обновляет через обнаруженный канал, `--via npm|brew` выбирает канал явно.
|
|
58
34
|
|
|
59
|
-
|
|
35
|
+
## Возможности
|
|
60
36
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
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 ресурс считается неполным переносом. |
|
|
66
59
|
|
|
67
|
-
##
|
|
60
|
+
## Совместимость
|
|
68
61
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
62
|
+
| Source | Destination |
|
|
63
|
+
| --- | --- |
|
|
64
|
+
| Yandex Wiki | Confluence, Yandex Wiki, Markdown, HTML |
|
|
65
|
+
| Confluence | Yandex Wiki, Confluence, Markdown, HTML |
|
|
66
|
+
|
|
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-версии.
|
|
72
74
|
|
|
73
75
|
## Конфигурация
|
|
74
76
|
|
|
75
|
-
|
|
77
|
+
Рабочий каталог выбирается в порядке `--workdir` → `ywtc.config.yaml` непосредственно в текущем каталоге → `~/.ywtc`. Родительские каталоги не просматриваются.
|
|
76
78
|
|
|
77
79
|
```text
|
|
78
80
|
~/.ywtc/
|
|
79
|
-
├── ywtc.config.yaml
|
|
80
|
-
└── .states/
|
|
81
|
+
├── ywtc.config.yaml # подключения, настройки и токены
|
|
82
|
+
└── .states/ # state, cache, backups и отчёты
|
|
81
83
|
```
|
|
82
84
|
|
|
83
|
-
`ywtc init --interactive`
|
|
84
|
-
|
|
85
|
-
`ywtc migrate --interactive` использует тот же порядок выбора workspace, последовательно настраивает source, destination, scope, комментарии и файловый ZIP, а затем по умолчанию запускает dry-run. После него можно открыть отчёт, изменить параметры, повторить проверку или явно начать live-перенос. При неполном inventory, root error, `failed`, `blocked` или настоящем `conflict` live-действие скрывается.
|
|
86
|
-
|
|
87
|
-
Обычный `ywtc init` без wizard создаёт безопасный пустой шаблон для автоматизации или ручного управления. Полный пример с Yandex Wiki, Confluence Data Center, Confluence Cloud и сетевыми лимитами: [`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).
|
|
88
86
|
|
|
89
|
-
### Поля
|
|
87
|
+
### Поля `ywtc.config.yaml`
|
|
90
88
|
|
|
91
|
-
| Поле |
|
|
89
|
+
| Поле | Профиль | Значения / default | Назначение |
|
|
92
90
|
| --- | --- | --- | --- |
|
|
93
|
-
| `defaults.timeoutMs` |
|
|
94
|
-
| `defaults.concurrency` |
|
|
95
|
-
| `connections.<name>` |
|
|
96
|
-
| `type` |
|
|
97
|
-
| `token` |
|
|
98
|
-
| `apiUrl` | Yandex Wiki | URL
|
|
99
|
-
| `
|
|
100
|
-
| `
|
|
101
|
-
| `organization.
|
|
102
|
-
| `
|
|
103
|
-
| `
|
|
104
|
-
| `
|
|
105
|
-
| `
|
|
106
|
-
| `
|
|
107
|
-
| `limits.
|
|
108
|
-
| `limits.
|
|
109
|
-
| `limits.
|
|
110
|
-
| `limits.
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
Confluence Server, Data Center Basic Auth и OAuth app-flow не поддерживаются. Совместимость определяется preflight-проверкой необходимых API/capabilities, а не сертификацией каждой patch-версии.
|
|
134
|
-
|
|
135
|
-
## Как получить токены
|
|
136
|
-
|
|
137
|
-
### Yandex Wiki
|
|
138
|
-
|
|
139
|
-
- [ ] Создайте приложение в [Яндекс OAuth](https://oauth.yandex.ru/).
|
|
140
|
-
- [ ] Выдайте права Wiki на чтение; для destination также нужны права записи.
|
|
141
|
-
- [ ] Получите OAuth-токен пользователя с доступом к страницам. Для федеративного пользователя Yandex Cloud допустим IAM-токен и `authType: iam`.
|
|
142
|
-
- [ ] Найдите ID организации в **Yandex Tracker → Администрирование → Организации**.
|
|
143
|
-
- [ ] Укажите `organization.type: yandex360` для Яндекс 360 или `cloud` для Cloud Organization.
|
|
144
|
-
- [ ] Запишите токен в `connections.<name>.token` выбранного профиля.
|
|
145
|
-
|
|
146
|
-
### Confluence Data Center
|
|
147
|
-
|
|
148
|
-
- [ ] Откройте **Avatar → Settings → Personal access tokens → Create token**.
|
|
149
|
-
- [ ] Создайте PAT и запишите его в `connections.<name>.token`.
|
|
150
|
-
- [ ] Используйте `deployment: data-center` и `authType: pat`.
|
|
151
|
-
- [ ] Проверьте права на чтение source и создание/изменение страниц и вложений destination.
|
|
152
|
-
|
|
153
|
-
### Confluence Cloud
|
|
154
|
-
|
|
155
|
-
- [ ] Создайте [Atlassian API token](https://id.atlassian.com/manage-profile/security/api-tokens).
|
|
156
|
-
- [ ] Используйте `deployment: cloud`, `authType: api-token`, `token` и `email`.
|
|
157
|
-
- [ ] Запишите API token и email аккаунта непосредственно в выбранный профиль.
|
|
158
|
-
- [ ] Проверьте доступ аккаунта к source и destination spaces.
|
|
159
|
-
|
|
160
|
-
## Параметры
|
|
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
|
|
161
131
|
|
|
162
132
|
### Команды
|
|
163
133
|
|
|
164
134
|
| Команда | Назначение |
|
|
165
135
|
| --- | --- |
|
|
166
|
-
| `ywtc init [
|
|
167
|
-
| `ywtc doctor [options]` | Проверить workspace; с source и destination выполнить read-only preflight |
|
|
168
|
-
| `ywtc migrate
|
|
169
|
-
| `ywtc migrate
|
|
170
|
-
| `ywtc reports list [
|
|
171
|
-
| `ywtc reports open [run-id\|last] [
|
|
172
|
-
| `ywtc update [
|
|
173
|
-
| `ywtc --help`, `ywtc <command> --help` | Показать общую или командную справку |
|
|
174
|
-
| `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]` | Проверить или установить обновление безопасным для текущего канала способом |
|
|
175
143
|
|
|
176
144
|
### Опции
|
|
177
145
|
|
|
178
|
-
| Полная
|
|
179
|
-
| --- | --- | --- |
|
|
180
|
-
| `--interactive
|
|
181
|
-
| `--workdir
|
|
182
|
-
| `--source
|
|
183
|
-
| `--destination
|
|
184
|
-
| `--source-profile
|
|
185
|
-
| `--destination-profile
|
|
186
|
-
| `--scope
|
|
187
|
-
| `--source-status
|
|
188
|
-
| `--comments` / `--no-comments
|
|
189
|
-
| `--format
|
|
190
|
-
| `--archive
|
|
191
|
-
| `--dry-run
|
|
192
|
-
| `--fresh
|
|
193
|
-
| `--open-report
|
|
194
|
-
| `--concurrency
|
|
195
|
-
| `--state
|
|
196
|
-
| `--install
|
|
197
|
-
| `--via
|
|
198
|
-
| `--help
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
-
|
|
206
|
-
-
|
|
207
|
-
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
- `
|
|
216
|
-
|
|
217
|
-
|
|
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
|
+
### Примеры
|
|
218
186
|
|
|
219
187
|
```bash
|
|
220
|
-
# Перенести
|
|
221
|
-
ywtc migrate
|
|
222
|
-
|
|
188
|
+
# Перенести структурное поддерево
|
|
189
|
+
ywtc migrate -s https://wiki.example.com/team/start \
|
|
190
|
+
-d https://confluence.example.com/confluence/pages/viewpage.action?pageId=123
|
|
223
191
|
|
|
224
|
-
# Перенести
|
|
225
|
-
ywtc migrate
|
|
226
|
-
|
|
227
|
-
|
|
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
|
|
228
196
|
|
|
229
|
-
# Создать автономный HTML
|
|
230
|
-
ywtc migrate
|
|
231
|
-
|
|
232
|
-
--format html --archive
|
|
197
|
+
# Создать автономный HTML и ZIP
|
|
198
|
+
ywtc migrate -s https://wiki.example.com/team/start \
|
|
199
|
+
-d ./exports/knowledge-base -f html -a
|
|
233
200
|
|
|
234
201
|
# Открыть последний корректный отчёт
|
|
235
202
|
ywtc reports open last
|
|
236
203
|
```
|
|
237
204
|
|
|
238
|
-
Wizard проверяет только доступность API и авторизацию без страниц и внешних записей. `doctor` принимает те же endpoints, profiles, `scope`, `source-status` и `format`: без endpoints он проверяет workspace, конфигурацию и секреты, а с обоими endpoints выполняет page-specific read-only capability-preflight.
|
|
239
|
-
|
|
240
205
|
## Файловый экспорт
|
|
241
206
|
|
|
242
|
-
Markdown создаёт `index.md`, `pages/`, `attachments
|
|
243
|
-
|
|
244
|
-
При включённых комментариях каждая страница получает секцию `Комментарии` с раскрываемыми ветками. Связанные из комментариев файлы находятся в одном ZIP рядом с attachments страницы; `manifest.json` внутри ZIP связывает source comment ID, исходную ссылку, исходное и архивное имя, размер и SHA-256.
|
|
245
|
-
|
|
246
|
-
Экспорт сначала строится в staging-каталоге. Существующий каталог заменяется только при строгом актуальном manifest с `tool: ywtc` и той же canonical identity, а прежний каталог сохраняется как timestamped backup. `--archive` оставляет каталог и создаёт новый ZIP, не перезаписывая существующий архив.
|
|
247
|
-
|
|
248
|
-
## State
|
|
207
|
+
Markdown создаёт `index.md`, `pages/`, `attachments/` и `.ywtc-export.json`. HTML создаёт автономный адаптивный сайт с локальным CSS, который работает через `file://` и на static hosting без CDN или внешнего runtime. `_source/` появляется только для страниц, которым нужен raw snapshot.
|
|
249
208
|
|
|
250
|
-
|
|
209
|
+
Внутренние ссылки и resources становятся относительными. Комментарии входят в страницу раскрываемыми ветками; явно связанные с ними файлы находятся в одном ZIP с `manifest.json`.
|
|
251
210
|
|
|
252
|
-
|
|
211
|
+
Экспорт строится в соседнем staging-каталоге. Существующий каталог заменяется только при актуальном manifest с `tool: ywtc` и той же canonical identity; предыдущая версия сохраняется как timestamped backup. `--archive` оставляет каталог и создаёт новый ZIP, не перезаписывая существующий.
|
|
253
212
|
|
|
254
|
-
|
|
255
|
-
- Переключение `current → all` расширяет тот же state новыми страницами без дубликатов; обратное переключение не удаляет mappings вне текущего выбора.
|
|
256
|
-
- Подтверждённая state-mapping означает, что source авторитетен: отличающийся body, title или parent mapped-страницы обновляется поверх актуальной destination-версии, а прежнее содержимое остаётся в истории провайдера.
|
|
257
|
-
- Если ранее страница была создана под временно ближайшим выбранным предком, повторный запуск перемещает mapped-страницу под найденного родителя до обработки потомков независимо от изменений её body.
|
|
258
|
-
- Уже сопоставленные страницы и вложения сверяются по ID, фактическому размеру и SHA-256; проверенный cache повторно не скачивается.
|
|
259
|
-
- Неудачные mappings вложений автоматически получают безопасные уникальные имена и повторяются без `--fresh`.
|
|
260
|
-
- Временный `404` подтверждённой destination-страницы повторяется с backoff; устойчиво пропавшая mapping восстанавливается под ожидаемым родителем с сохранением прежнего ID в state.
|
|
261
|
-
- Страница с прежним неизменённым служебным placeholder ywtc автоматически получает полноценный source-derived контент.
|
|
262
|
-
- Ошибка отдельного файла оставляет полный текст и source-ссылку, фиксирует `partial` и повторяет ресурс при следующем запуске.
|
|
263
|
-
- Неизменённые архивы комментариев и ZIP проверяются и переиспользуются без дубликатов. Mapped Confluence-архив обновляется новой версией из source, а Yandex Wiki получает новую архивную ревизию, поскольку Public API не предоставляет update comments.
|
|
264
|
-
- Удалённый mapped-комментарий создаётся заново. Исчезнувшие из доступного source API комментарии отмечаются `stale` и автоматически не удаляются.
|
|
265
|
-
- Запуск с `--no-comments` не обращается к comment API и не удаляет ранее созданные архивы; следующий обычный запуск дополнит тот же state.
|
|
266
|
-
- `conflict` используется только при доказанной неоднозначности immutable ownership/identity: несколько source mappings на один destination ID, несовпадение возвращённого immutable ID или несколько равноправных ownership-кандидатов. Версия, title, URL, slug, parent, fingerprint, HTTP `409`, слово `conflict` в сообщении и коллизия имени сами по себе конфликтом не являются.
|
|
267
|
-
- `--fresh` игнорирует mappings; перед live-run прежний state сохраняется как backup, а destination может получить новые объекты.
|
|
268
|
-
- Удалённые из source объекты автоматически не удаляются из destination.
|
|
213
|
+
## State и повторные запуски
|
|
269
214
|
|
|
270
|
-
|
|
215
|
+
State находится в `<workdir>/.states/<automatic-id>.json`. ID зависит от канонических профилей и page IDs, а для экспорта — ещё от формата; URL/ID/slug, `scope` и `source-status` его не меняют. Относительный `--state` разрешается только внутри workspace.
|
|
271
216
|
|
|
272
|
-
|
|
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 при этом может получить новые объекты.
|
|
273
224
|
|
|
274
|
-
|
|
225
|
+
Live-run использует exclusive lock; stale lock восстанавливается. При SIGINT/SIGTERM новые задачи не запускаются, безопасные активные операции завершаются, state и отчёт сохраняются. Коды выхода: `0` — completed, `1` — partial/verification failure, `2` — usage/config/preflight, `130`/`143` — сигнал.
|
|
275
226
|
|
|
276
|
-
|
|
227
|
+
## Отчёты и статусы
|
|
277
228
|
|
|
278
|
-
|
|
229
|
+
Каждый запуск создаёт `<workdir>/.states/reports/<run-id>/index.html` и очищенный `report.json`, затем печатает URL и команду открытия. Используйте `--open-report`, `ywtc reports list` или `ywtc reports open [run-id|last]`; без selector `open` также выбирает последний корректный отчёт.
|
|
279
230
|
|
|
280
|
-
|
|
231
|
+
Автономный отчёт показывает только ненулевые показатели, канонические source/destination, исходную иерархию, исключённые страницы и проблемы. Дерево поддерживает поиск и фильтры; детали страницы содержат доступные files, comments, side-by-side comparison и диагностику. RU/EN и system/light/dark переключаются иконками. `report.json` не содержит body страниц, тексты комментариев или preview HTML.
|
|
281
232
|
|
|
282
|
-
|
|
233
|
+
### Outcomes объектов
|
|
283
234
|
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
|
289
|
-
|
|
290
|
-
| `
|
|
291
|
-
| `
|
|
292
|
-
| `
|
|
293
|
-
| `blocked` | Страница не запускалась из-за недоступного failed/conflict родителя или другой зависимости | Нет в этом запуске | Исправить указанную upstream-ошибку и повторить запуск |
|
|
294
|
-
| `conflict` | Immutable ownership/identity destination доказанно неоднозначна, в отчёте перечислены кандидаты | Нет автоматической перезаписи | Проверить candidate IDs и устранить неоднозначное сопоставление |
|
|
295
|
-
| `planned` | Объект рассчитан в `--dry-run`; запись не выполнялась | Нет | Убрать `--dry-run` для переноса |
|
|
296
|
-
| `not-started` | Live-run остановился до начала независимой операции | Нет | Повторить ту же миграцию |
|
|
297
|
-
|
|
298
|
-
Статусы файлов:
|
|
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 остановился до независимой операции; повторить запуск |
|
|
299
244
|
|
|
300
|
-
|
|
301
|
-
|---|---|---:|---|
|
|
302
|
-
| `complete` | Файл загружен и проверен | Да | Ничего |
|
|
303
|
-
| `partial` | Файл доступен через сохранённый fallback, но нативная передача неполна | Частично | Проверить fallback и повторить retryable-операцию |
|
|
304
|
-
| `failed` | Download, upload или verification файла выполнялся и завершился ошибкой | Возможно частично | Проверить причину и повторить запуск |
|
|
305
|
-
| `blocked` | Файл не обрабатывался, потому что destination-страница недоступна | Нет в этом запуске | Сначала устранить указанную ошибку страницы |
|
|
306
|
-
| `planned` | Файл только запланирован в `--dry-run` | Нет | Запустить без `--dry-run` |
|
|
307
|
-
| `not-started` | Live-run прерван до начала обработки файла | Нет | Повторить ту же миграцию |
|
|
245
|
+
### Качество преобразования
|
|
308
246
|
|
|
309
|
-
|
|
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 и объекта |
|
|
310
255
|
|
|
311
|
-
|
|
256
|
+
Итог запуска: `completed`, `completed-with-warnings`, `partial`, `failed`, `cancelled` или `interrupted`. HTML, JSON, terminal summary и `reports list` используют одинаковые totals; зависимые `blocked` объекты не считаются отдельными root errors.
|
|
312
257
|
|
|
313
258
|
## Разработка
|
|
314
259
|
|
|
@@ -320,6 +265,6 @@ npm run workspace:init
|
|
|
320
265
|
npm run check
|
|
321
266
|
```
|
|
322
267
|
|
|
323
|
-
`npm run check` запускает
|
|
268
|
+
`npm run check` запускает release hygiene и security audit, TypeScript, Biome, Knip, Vitest, Playwright, сборку, package smoke-test и строгую OpenSpec-валидацию. Любое изменение проходит цикл из [`AGENTS.md`](AGENTS.md).
|
|
324
269
|
|
|
325
|
-
Release Please рассчитывает SemVer из Conventional Commits. После merge release PR GitHub Actions
|
|
270
|
+
Release Please рассчитывает SemVer из Conventional Commits. После merge release PR GitHub Actions публикует GitHub Release и npm-пакет с OIDC provenance, затем генерирует, устанавливает и тестирует Homebrew-формулу.
|