Skip to content

Repository files navigation

Confluence Page Sync v2.19.0

Русский | English

Утилита командной строки для синхронизации страниц Confluence с локальной структурой папок.

Инструмент поддерживает:

  • скачивание страниц из Confluence на диск с принудительной перезаписью (download update) или умным слиянием (download merge)
  • загрузку локальных страниц обратно в Confluence с принудительной перезаписью (upload update), умным слиянием (upload merge) или созданием новых (upload create)
  • сравнение дерева страниц в Confluence с локальным снимком (compare)
  • просмотр действующей конфигурации с указанием источников значений (config show)

Основные возможности

  • Git-подобная модель синхронизации: update (force) и merge (smart)
  • Определение конфликтов: если страница изменена и локально, и на сервере — конфликт выявляется, перезапись не выполняется, пользователь получает предупреждение
  • Отчёт --report — сводка страниц, требующих ручного разрешения (конфликты, удалённые страницы)
  • Выбор страницы по --page-id или --page-title
  • Опциональная рекурсивная обработка (--recursive)
  • Работа с несколькими пространствами: пространство страницы сохраняется в маркере и берётся с сервера; деревья из разных пространств можно держать рядом и синхронизировать вместе (--multi-tree для upload). Непреднамеренный перенос поддерева в чужое пространство отклоняется и попадает в отчёт
  • Формат локального снимка:
    • одна папка на страницу (имя папки = заголовок страницы, с sanitization под файловую систему)
    • файл index.html с контентом страницы в storage representation
    • вложения как отдельные файлы
    • файл-маркер .id<pageId>_<version> (в теле — JSON с оригинальным заголовком и ключом пространства) для стабильной идентификации страницы и отслеживания версии
  • Режимы аутентификации: --auth-type onprem и --auth-type cloud; по умолчанию тип определяется автоматически по --base-url (хосты *.atlassian.netcloud)
  • Полная поддержка Confluence Cloud (REST API v2 + сохранившиеся v1-эндпоинты): все команды — download, upload, compare, вложения — работают одинаково на Server/DC и Cloud; числовые идентификаторы пространств Cloud прозрачно резолвятся из ключей
  • Многоуровневая конфигурация с приоритетом: CLI > переменные окружения > файл > значение по умолчанию
  • Глобальный параметр --verbose для подробного (debug-level) вывода
  • Поддержка dry-run там, где применимо

Локальная структура хранения

При выгрузке (download update/download merge) страницы сохраняются в иерархию папок внутри --output-dir. Каждая папка страницы содержит контент, маркер идентификатора и вложения.

<output-dir>/
  Root Page/
    index.html
    .id12345_7
    image.png
    spec.pdf
    Child Page A/
      index.html
      .id23456_3
    Child Page B/
      index.html
      .id34567_1

Правила:

  • имя папки страницы = заголовок страницы в Confluence (каждый недопустимый символ заменяется на _); оригинальный заголовок сохраняется в маркере .id* и восстанавливается при загрузке на сервер; переименование папки пользователем интерпретируется как намерение переименовать страницу
  • index.html содержит body.storage.value
  • файл .id<pageId>_<version> используется для стабильного сопоставления при синхронизации и сравнении; суффикс _<version> отражает номер версии страницы на сервере в момент последней синхронизации; время последней записи маркера (LastWriteTimeUtc) используется как точка отсчёта для определения конфликтов; содержимое файла хранит оригинальный заголовок страницы Confluence для восстановления при загрузке на сервер
  • все файлы, кроме index.html и .id*, считаются вложениями страницы

Переносимость зеркала между ОС

Санитизация имён папок выполняется по правилам файловой системы, на которой создаётся зеркало: на Windows заменяются символы < > : " / \ | ? * и управляющие, на Linux/macOS — только / и \0. Это значит, что зеркало привязано к ОС, на которой оно создано:

  • заголовок Модуль "Провайдеры" на Windows даст папку Модуль _Провайдеры_, а на Linux — Модуль "Провайдеры" (такое имя папки на Windows создать нельзя);
  • прямое копирование зеркала между ОС (через облачные папки, scp/rsync, сетевые шары) может привести к невалидным именам или к тому, что утилита перестанет узнавать уже синхронизированные страницы.

Рекомендуемый сценарий при смене рабочей машины — заново выгрузить зеркало с сервера Confluence через download update или download merge, а не копировать существующую локальную папку.

Правило для AI-ассистентов

В папке docs/ai-rules/ лежит файл local-mirror-format.mdc — описание структуры и формата локального зеркала Confluence, которое можно подключить к вашему AI-ассистенту (Cursor, Claude Code, Continue, Aider, Windsurf и др.), чтобы он корректно понимал иерархию папок, формат index.html (Confluence Storage Format), маркеры .id* и вложения при работе с выгруженным деревом страниц.

Инструкции по подключению для разных инструментов — в docs/ai-rules/README.md.

MCP-сервер для ИИ-агентов

Утилиту можно запустить как MCP-сервер по stdio — это даёт ИИ-агентам (Claude Desktop, Cursor, Codex и др.) возможность выполнять шесть операций синхронизации (download update/merge, upload update/create/merge, compare) прямо из чата, без перехода в терминал, плюс два helper-инструмента для самодиагностики и agent-assisted merge:

  • confluence_ping — лёгкая проверка связности и учётных данных (base URL, текущий пользователь, latency, sandbox-настройки); доступна и в --read-only.
  • confluence_get_page_content — получение storage-format XHTML страницы (текущая или историческая версия) для сценария «конфликт → diff → merge», когда агент локально читает index.html своими файловыми инструментами и сводит правки. Поддерживает 2-way и 3-way merge (через version из локального маркера .idPAGEID_VER).
ConfluencePageExporter mcp --root-dir <path> [--read-only]
  • --root-dir — обязательная песочница: агент не может писать вне неё.
  • --read-only — блокирует upload-инструменты (download/compare/ping/get_page_content остаются).
  • Параметры подключения к Confluence (BaseUrl/Username/Token/SpaceKey/AuthType) задаются через env-переменные CONFLUENCE_EXPORTER__* или JSON-конфиг — они никогда не попадают в context window LLM.
  • Сервер автоматически передаёт агенту короткий гайд по использованию через MCP InitializeResult.Instructions — большинство клиентов подмешивают это в системный промпт без ручных действий.

Подробное описание инструментов, формата результатов, кодов ошибок, сценарии 2-/3-way merge, гайд для агента и готовые конфиги для Claude Desktop / Cursor / Codex — в docs/mcp/.

Установка

Готовые сборки публикуются на GitHub Releases как self-contained single-file архивы — .NET Runtime ставить не нужно.

Платформа Архив
Windows x64 ConfluencePageExporter-v<версия>-win-x64.zip
Linux x64 ConfluencePageExporter-v<версия>-linux-x64.tar.gz
macOS arm64 ConfluencePageExporter-v<версия>-osx-arm64.tar.gz

После распаковки архива получаете один исполняемый файл (ConfluencePageExporter.exe или ConfluencePageExporter), README.md, README.en.md и LICENSE. На macOS/Linux потребуется chmod +x ConfluencePageExporter.

Сборка из исходников

dotnet build

Самостоятельная публикация self-contained single-file сборки:

dotnet publish src/ConfluencePageExporter -c Release -r <RID> \
  --self-contained true \
  -p:PublishSingleFile=true \
  -p:IncludeNativeLibrariesForSelfExtract=true \
  -p:EnableCompressionInSingleFile=true

где <RID> — один из win-x64, linux-x64, linux-arm64, osx-arm64, osx-x64.

Конфигурация

Утилита использует стандартный Microsoft.Extensions.Configuration pipeline. Параметры читаются из нескольких источников с приоритетом (последний побеждает):

  1. JSON-файл — по умолчанию confluence-exporter.json в текущей директории; путь можно указать явно через --config <path>.
  2. Переменные окружения — с префиксом CONFLUENCE_EXPORTER__, двойное подчёркивание разделяет секции (например, CONFLUENCE_EXPORTER__GLOBAL__BASEURL).
  3. Параметры командной строки — явно заданные CLI-аргументы имеют наивысший приоритет.

Глобальные параметры

Указываются перед именем команды:

  • --config <path> — путь к JSON-файлу конфигурации
  • --verbose — включить подробный (debug-level) вывод в лог
  • --report — вывести сводку страниц, требующих ручной обработки, после завершения команды
  • --max-parallelism N — максимальное число одновременных операций при обходе дерева страниц в download/upload (по умолчанию 8; 1 отключает параллелизм)

Пример confluence-exporter.json

{
  "Global": {
    "BaseUrl": "https://wiki.example.com",
    "Username": "user@example.com",
    "Token": "token-or-password",
    "SpaceKey": "DOCS",
    "AuthType": "onprem",
    "DryRun": false,
    "Recursive": true,
    "Report": false,
    "MaxParallelism": 8
  },
  "Download": {
    "PageId": "12345",
    "OutputDir": "./export",
    "Merge": {
      "OutputDir": "./export-merge"
    }
  },
  "Upload": {
    "SourceDir": "./export",
    "Update": {
      "PageId": "67890"
    },
    "Create": {
      "ParentTitle": "Architecture"
    },
    "Merge": {
      "PageTitle": "MyPage"
    }
  },
  "Compare": {
    "OutputDir": "./export",
    "MatchByTitle": true,
    "DetectSource": false
  }
}

Наследование параметров

Конфигурация поддерживает двухуровневую модель: общие параметры команды наследуются подкомандами и могут быть переопределены на уровне подкоманды.

Цепочка разрешения значений (от высшего приоритета к низшему):

  1. Секция подкоманды — например, Download:Update:OutputDir
  2. Секция команды — например, Download:OutputDir
  3. Global — для параметра Recursive (fallback в коде хэндлера)
  4. Значение по умолчаниюfalse / null

Пример: если в JSON указан "Download": { "PageId": "12345", "OutputDir": "./export", "Merge": { "OutputDir": "./export-merge" } }, то:

  • download update получит PageId = 12345, OutputDir = ./export (наследование от Download)
  • download merge получит PageId = 12345 (наследование), OutputDir = ./export-merge (переопределение)

Переменные окружения

Переменные окружения именуются по формату CONFLUENCE_EXPORTER__<Секция>__<Параметр> (всё в верхнем регистре):

export CONFLUENCE_EXPORTER__GLOBAL__BASEURL=https://wiki.example.com
export CONFLUENCE_EXPORTER__GLOBAL__USERNAME=user@example.com
export CONFLUENCE_EXPORTER__GLOBAL__TOKEN=secret
export CONFLUENCE_EXPORTER__DOWNLOAD__OUTPUTDIR=./export
export CONFLUENCE_EXPORTER__DOWNLOAD__UPDATE__PAGEID=12345
export CONFLUENCE_EXPORTER__UPLOAD__SOURCEDIR=./export

Формат вызова

ConfluencePageExporter [глобальные параметры] <команда подкоманда> [параметры команды]

Обзор команд

ConfluencePageExporter download update ...    # принудительное скачивание (сервер → локально)
ConfluencePageExporter download merge ...     # умное скачивание с сохранением локальных правок
ConfluencePageExporter upload update ...      # принудительная загрузка (локально → сервер)
ConfluencePageExporter upload merge ...       # умная загрузка с сохранением серверных правок
ConfluencePageExporter upload create ...      # создание новых страниц
ConfluencePageExporter compare ...            # сравнение и отчёт
ConfluencePageExporter config show            # отображение конфигурации

Модель синхронизации

Утилита использует git-подобную модель с двумя режимами:

Режим Описание
update Принудительная синхронизация. Источник считается эталоном, целевая сторона перезаписывается. Локальные/серверные правки на целевой стороне будут потеряны.
merge Умная синхронизация. Перезаписываются только страницы, изменённые на стороне-источнике. Правки на целевой стороне сохраняются. Страницы с конфликтом (двойные правки) пропускаются с предупреждением.

Типичные сценарии использования

# Полностью скачать серверную версию, затерев локальные изменения
ConfluencePageExporter download update --page-id 12345 --output-dir ./export --recursive

# Скачать только серверные обновления, сохранив локальные правки
ConfluencePageExporter download merge --page-id 12345 --output-dir ./export --recursive

# Загрузить локальные изменения на сервер, затерев серверные
ConfluencePageExporter upload update --source-dir ./export/MyPage --recursive

# Загрузить только локальные обновления, сохранив серверные правки
ConfluencePageExporter upload merge --source-dir ./export/MyPage --recursive

# Двусторонняя синхронизация (сохраняются самые новые изменения с обеих сторон)
ConfluencePageExporter download merge --page-id 12345 --output-dir ./export --recursive --report
ConfluencePageExporter upload merge --source-dir ./export/MyPage --recursive --report

Определение конфликтов

В режиме merge утилита использует маркер .id<pageId>_<version> для определения конфликтов:

  • syncTimeUtc = время последней записи маркерного файла (момент последней синхронизации)
  • serverChanged = серверная версия новее версии в маркере
  • localChanged = файл index.html изменён после syncTimeUtc
  • Если оба флага trueконфликт: страница не перезаписывается ни в одну сторону, выводится предупреждение

При наличии ключа --report после завершения команды выводится сводка всех страниц, требующих ручного разрешения.

Отдельным разделом отчёта выводятся несинхронизированные вложения — файлы, которые не удалось скачать или загрузить (например, сервер потерял двоичное содержимое и отвечает ошибкой на ссылку скачивания), а также страницы, для которых не удалось получить список вложений. Это расхождение зеркала, поэтому предупреждение о таких вложениях выводится и без --report.

Команда download update

Принудительно скачивает страницу Confluence (или поддерево) на локальный диск. Различающиеся страницы перезаписываются серверными версиями. Локальные правки будут потеряны.

Параметры download update

  • --base-url (обязательный)
  • --username (обязательный)
  • --token (обязательный)
  • --space-key (обязательный)
  • --page-id или --page-title (обязательно указать ровно один)
  • --output-dir (обязательный)
  • --recursive (опционально)
  • --auth-type onprem|cloud (опционально, по умолчанию — автоопределение по --base-url)
  • --dry-run (опционально)
  • --report (опционально)

Пример download update

ConfluencePageExporter download update \
  --base-url https://wiki.example.com \
  --username user@example.com \
  --token <token> \
  --space-key DOCS \
  --page-id 12345 \
  --recursive \
  --output-dir ./export

Команда download merge

Скачивает страницы с сервера, перезаписывая только те, которые новее на сервере. Локальные правки сохраняются. Конфликты (двойные правки) пропускаются с предупреждением.

Параметры download merge

  • --base-url (обязательный)
  • --username (обязательный)
  • --token (обязательный)
  • --space-key (обязательный)
  • --page-id или --page-title (обязательно указать ровно один)
  • --output-dir (обязательный)
  • --recursive (опционально)
  • --auth-type onprem|cloud (опционально, по умолчанию — автоопределение по --base-url)
  • --dry-run (опционально)
  • --report (опционально)

Пример download merge

ConfluencePageExporter --report download merge \
  --base-url https://wiki.example.com \
  --username user@example.com \
  --token <token> \
  --space-key DOCS \
  --page-id 12345 \
  --recursive \
  --output-dir ./export

Команда upload update

Принудительно загружает локальные страницы на сервер. Различающиеся страницы перезаписываются локальными версиями. Серверные правки будут потеряны. Перемещение страниц при расхождении родителя выполняется автоматически.

Параметры upload update

  • --base-url (обязательный)
  • --username (обязательный)
  • --token (обязательный)
  • --space-key (обязательный)
  • --source-dir (обязательный)
  • --page-id или --page-title (опционально, явное указание корневой страницы)
  • --recursive (опционально)
  • --multi-tree (опционально; --source-dir указывает на каталог с несколькими деревьями — каждое обрабатывается со своим пространством; несовместимо с --page-id/--page-title)
  • --auth-type onprem|cloud (опционально, по умолчанию — автоопределение по --base-url)
  • --dry-run (опционально)
  • --report (опционально)

Приоритет определения корневой страницы

  1. Явно заданные --page-id / --page-title
  2. Локальный файл-маркер .id<pageId>_<version> в source-dir
  3. Имя папки source-dir как заголовок страницы

Если корневая страница не найдена, команда завершается ошибкой.

Пропуск неизменённых страниц

Перед отправкой обновления утилита сравнивает локальный контент с серверным. Если заголовок, контент и родительская страница не изменились, обновление пропускается — это предотвращает создание лишних версий на сервере.

Обновление вложений

Вложения обновляются через версионирование Confluence (создание новой версии файла). Перед загрузкой проверяется, изменился ли файл (по размеру и SHA-256 хэшу). Неизменённые вложения пропускаются.

Пример upload update

ConfluencePageExporter upload update \
  --base-url https://wiki.example.com \
  --username user@example.com \
  --token <token> \
  --space-key DOCS \
  --source-dir ./export/MyPage \
  --recursive

Команда upload merge

Загружает на сервер только локально изменённые страницы. Серверные правки сохраняются. Конфликты (двойные правки) пропускаются с предупреждением.

Дополнительно upload merge распознаёт структурные изменения локального дерева:

  • Локальное перемещение папки (новая родительская папка имеет свой .id-маркер) — выполняется перемещение страницы на сервере (ancestors) в одном вызове API.
  • Новая папка внутри уже синхронизированного поддерева — создаётся как страница на сервере с правильным родителем и с автоматической записью локального .id-маркера. Использовать upload create для одиночных новых страниц внутри существующей иерархии не нужно.

Если контент той же страницы был изменён и на сервере, структурное перемещение откладывается: страница попадает в раздел Skipped с подсказкой выполнить download merge, переместить папку заново и повторить upload merge.

Параметры upload merge

  • --base-url (обязательный)
  • --username (обязательный)
  • --token (обязательный)
  • --space-key (обязательный)
  • --source-dir (обязательный)
  • --page-id или --page-title (опционально, явное указание корневой страницы)
  • --recursive (опционально)
  • --multi-tree (опционально; --source-dir указывает на каталог с несколькими деревьями — каждое обрабатывается со своим пространством; несовместимо с --page-id/--page-title)
  • --auth-type onprem|cloud (опционально, по умолчанию — автоопределение по --base-url)
  • --dry-run (опционально)
  • --report (опционально)

Пример upload merge

ConfluencePageExporter --report upload merge \
  --base-url https://wiki.example.com \
  --username user@example.com \
  --token <token> \
  --space-key DOCS \
  --source-dir ./export/MyPage \
  --recursive

Команда upload create

Создает новые страницы Confluence по локальному содержимому.

Параметры upload create

  • --base-url (обязательный)
  • --username (обязательный)
  • --token (обязательный)
  • --space-key (обязательный)
  • --source-dir (обязательный)
  • --parent-id или --parent-title (опционально)
  • --recursive (опционально)
  • --auth-type onprem|cloud (опционально, по умолчанию — автоопределение по --base-url)
  • --dry-run (опционально)

Пример upload create

ConfluencePageExporter upload create \
  --base-url https://wiki.example.com \
  --username user@example.com \
  --token <token> \
  --space-key DOCS \
  --parent-id 67890 \
  --source-dir ./export/NewPage \
  --recursive

Команда compare

Сравнивает дерево страниц в Confluence с локальным снимком и выводит отчет. Для каждого обнаруженного различия определяется вероятный источник изменения (сервер или локально) на основе сравнения дат модификации. При использовании --detect-source дополнительно анализируется история версий Confluence для повышения точности определения источника переименований и перемещений.

Параметры compare

  • --base-url (обязательный)
  • --username (обязательный)
  • --token (обязательный)
  • --space-key (обязательный)
  • --page-id или --page-title (обязательно указать ровно один)
  • --output-dir (обязательный)
  • --recursive (опционально)
  • --match-by-title (опционально)
  • --detect-source (опционально) — анализировать историю версий для определения источника переименований и перемещений (дополнительные API-вызовы)
  • --auth-type onprem|cloud (опционально, по умолчанию — автоопределение по --base-url)

Стратегия сопоставления

  • по умолчанию: сопоставление локальных страниц по .id<pageId>_<version>
  • с --match-by-title: если .id отсутствует, используется fallback-сопоставление по заголовкам/пути папок

Определение источника изменений

Для каждого обнаруженного различия утилита пытается определить, где произошло изменение — локально или на сервере. Используется два уровня эвристик:

  1. Сравнение версий маркера (для контента, если доступен .id<pageId>_<version>) — если версия маркера совпадает с серверной, изменение локальное; если серверная версия новее — изменение на сервере. Достоверность: высокая.

  2. Сравнение дат (всегда, как fallback) — сопоставляет дату последней модификации серверной страницы (version.when) с датой изменения локальной папки (переименование/перемещение) или файла index.html (контент). Достоверность: средняя.

  3. Анализ истории версий--detect-source) — для переименований ищет прежний заголовок в истории версий страницы, для перемещений ищет прежнего родителя в ancestors исторических версий. Достоверность: высокая.

Пример compare

ConfluencePageExporter compare \
  --base-url https://wiki.example.com \
  --username user@example.com \
  --token <token> \
  --space-key DOCS \
  --page-id 12345 \
  --recursive \
  --match-by-title \
  --detect-source \
  --output-dir ./export

Пример вывода:

Compare report
==============
Added in Confluence: 1
  + [55555] New Page (Root/New Page)
Deleted in Confluence: 0
Renamed/moved: 1
  ~ [12345] New Title | local: Root/Old Title -> confluence: Root/New Title
    Переименование: СЕРВЕР (высокая) — заголовок 'Old Title' найден в серверной версии 3
Content changed: 1
  * [23456] Some Page (Root/Some Page)
    Источник: ЛОКАЛЬНО (средняя) — локальный файл изменён (2026-03-12) позже сервера (2026-03-10)

Команда config show

Выводит текущую действующую конфигурацию с указанием источника каждого значения.

Возможные источники:

  • [CLI] — задано аргументом командной строки
  • [ENV] — задано переменной окружения
  • [FILE] — задано в JSON-файле конфигурации
  • [DEFAULT] — значение по умолчанию

Пример config show

ConfluencePageExporter config show

Пример вывода:

Effective configuration
=======================

Global:
  BaseUrl                      = https://wiki.example.com            [FILE]
  Username                     = user@example.com                    [FILE]
  Token                        = to***en                             [FILE]
  SpaceKey                     = DOCS                                [FILE]
  AuthType                     = onprem                              [DEFAULT]
  Verbose                      = False                               [DEFAULT]
  DryRun                       = False                               [DEFAULT]
  Recursive                    = True                                [FILE]
  Report                       = False                               [DEFAULT]

Подробное логирование

Для включения debug-level вывода используйте глобальный параметр --verbose:

ConfluencePageExporter --verbose download update \
  --page-id 12345 \
  --output-dir ./export

Миграция с v1.x

В версии 2.0 произведены ломающие изменения в структуре команд:

v1.x v2.0 Описание
download download update Принудительное скачивание
download merge Умное скачивание (новая команда)
upload update --on-error abort upload update Параметр --on-error удалён; при ошибке выполнение прерывается
upload update --move-pages upload update Параметр --move-pages удалён; перемещение выполняется автоматически
download --overwrite-strategy overwrite download update Параметр --overwrite-strategy удалён
upload merge Умная загрузка (новая команда)
--report Отчёт о страницах с конфликтами (новый глобальный ключ)

About

CLI and MCP server for two-way syncing Confluence Server / Data Center / Cloud pages with a local filesystem mirror.

Topics

Resources

Stars

5 stars

Watchers

0 watching

Forks

Releases

Contributors

Languages