Загрузка данных


Ты работаешь в текущем проекте:

/home/work/skil-scrap/adt-markdownify-meta

Задача:
Реализовать только файл:

scripts/markdown_writer.py

Важно:
- Не трогай другие файлы.
- Не меняй config_loader.py.
- Не меняй README.md.
- Не меняй SKILL.md.
- Не меняй run_exporter.py.
- Сейчас нужна только логика сохранения Markdown-файлов.

Нужно реализовать:

1. Функцию safe_filename(name: str) -> str

Логика:
- принимает название страницы;
- заменяет запрещённые символы на "_";
- запрещённые символы: \ / : * ? " < > | ;
- убирает лишние пробелы;
- заменяет несколько пробелов на один;
- если после очистки имя пустое, возвращает "meta_page".

2. Функцию write_markdown(output_dir: str, title: str, url: str, markdown_body: str) -> Path

Логика:
- создаёт папку output_dir, если её нет;
- формирует безопасное имя файла из title;
- добавляет расширение .md;
- сохраняет Markdown-файл;
- в начало файла добавляет:

# {title}

Источник: {url}

---

- ниже добавляет markdown_body;
- возвращает Path к созданному файлу.

3. Функцию write_index(output_dir: str, exported_files: list) -> Path

Логика:
- создаёт файл README.md внутри output_dir;
- добавляет заголовок:

# META export

- добавляет список выгруженных файлов;
- exported_files — это список словарей формата:
  {
    "title": "Название",
    "url": "https://...",
    "path": Path(...)
  }

- для каждого файла добавляет строку:
  - [Название](имя_файла.md) — https://...

- возвращает Path к README.md.

Требования:
- Используй pathlib.Path.
- Код должен быть простым и понятным.
- Не используй API.
- Не используй requests/httpx/aiohttp/urllib.
- Не добавляй токены, cookie, login, password.
- Все файлы сохраняй в кодировке utf-8.

После реализации покажи полный код файла scripts/markdown_writer.py.