Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 23 additions & 5 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
name: CI

# Бесплатный детерминированный гейт: синтаксис обеих версий обёртки + smoke-тесты
# арг-парсинга и graceful-поведения. Реальную конвертацию форматов CI НЕ гоняет:
# это требовало бы скачивания бинарника anydoc из сети на каждый прогон и
# зависело бы от внешнего пакета — недетерминированно. Живые проверки форматов
# делаются вручную (см. skills/doc2md/SKILL.md, раздел «Протестировано»).
# Быстрый офлайн smoke-гейт и отдельная проверка Windows с закреплённой
# версией anydoc. Полную матрицу форматов CI не гоняет; см. SKILL.md.

on:
pull_request:
Expand Down Expand Up @@ -38,3 +35,24 @@ jobs:
gemini-extension.json; do
node -e "JSON.parse(require('fs').readFileSync('$f','utf8')); console.log('ok: $f')"
done

windows-paths:
runs-on: windows-latest
steps:
- uses: actions/checkout@v7
- uses: actions/setup-node@v7
with:
node-version: "20"
- name: Install anydoc for the Windows path test
run: npm install -g @firecrawl/anydoc@0.2.4
- name: Spaces, percent signs, and output collisions
shell: pwsh
run: |
New-Item -ItemType Directory -Force 'test-input/a', 'test-input/b', 'test-output' | Out-Null
Set-Content -LiteralPath 'test-input/a/a %TEMP% b.csv' -Value "name,value`na,1" -NoNewline
Set-Content -LiteralPath 'test-input/a/dup.csv' -Value "name,value`na,2" -NoNewline
Set-Content -LiteralPath 'test-input/b/dup.csv' -Value "name,value`nb,3" -NoNewline
node skills/doc2md/scripts/convert.js test-input/a test-input/b -o test-output
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
if (-not (Test-Path -LiteralPath 'test-output/a %TEMP% b.csv.md')) { throw 'Special-character path was lost' }
if ((Get-ChildItem -LiteralPath test-output -Filter 'dup.csv.*.md').Count -ne 2) { throw 'Output collision lost a file' }
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ doc2md/
│ ├── SKILL.md — сам скилл (описание + инструкция для агента)
│ └── scripts/
│ ├── convert.js — пакетный конвертер, кросс-платформенный (Windows/macOS/Linux) — основной
│ └── convert.sh — тот же конвертер, bash-версия для Unix
│ └── convert.sh — совместимый bash-вход, вызывает convert.js
├── commands/convert.md — слэш-команда /convert
├── .claude-plugin/ — манифесты для Claude Code + marketplace
├── .codex-plugin/ — манифест для Codex CLI
Expand Down Expand Up @@ -94,13 +94,13 @@ node skills/doc2md/scripts/convert.js ~/Downloads/акты/ -o ~/Downloads/ак
node skills/doc2md/scripts/convert.js a.pdf b.xlsx "отчёт за март.pptx"
```

На Unix (macOS/Linux/WSL/Git Bash) — bash-версия, поведение идентично:
На Unix (macOS/Linux/WSL/Git Bash) можно вызвать тот же конвертер через bash:

```bash
bash skills/doc2md/scripts/convert.sh договор.docx
```

Без `-o` каждый файл `<имя>.<расширение>.md` пишется рядом с исходником — расширение сохраняется в имени намеренно, иначе `отчёт.docx` и `отчёт.csv` в одной папке лягут в один `отчёт.md` и один перезапишет другой. С `-o папка/` все результаты собираются в одном месте.
Без `-o` каждый файл `<имя>.<расширение>.md` пишется рядом с исходником — расширение сохраняется в имени намеренно. С `-o папка/` все результаты собираются в одном месте; тёзки из разных подпапок получают суффикс пути, чтобы не перезаписать друг друга.

Триггеры для агента: «сконвертируй эти файлы», «разбери пачку документов», «не могу прочитать этот файл», «переведи в markdown», «подготовь документы для агента».

Expand All @@ -119,10 +119,10 @@ bash skills/doc2md/scripts/convert.sh договор.docx
## Что скрипт делает, а что нет

- Конвертирует файл(ы), печатает построчный статус и итоговую сводку: сколько `OK`, сколько `ПРОПУСК`, сколько `ОШИБКА`.
- **`OK`** — anydoc вернул код `0`. **`ОШИБКА`** — не удалось даже запустить `npx`/anydoc (нет в PATH, код 126/127): отказ окружения, а не «файл нечитаем», OCR тут не поможет. **`ПРОПУСК`** — anydoc запустился, но файл не сконвертировался: почти всегда скан/шифр/битый файл.
- **`OK`** — anydoc вернул код `0` и результат записан. **`ПРОПУСК`** — код `3`: PDF нужны OCR-страницы. **`ОШИБКА`** — прочий сбой чтения, конвертации, записи или вызова; пакет завершится с ненулевым кодом.
- Не удаляет и не трогает исходники.

> Контракт кодов возврата anydoc формально не задокументирован — скрипт трактует их консервативно (см. `SKILL.md`). При первом боевом прогоне на битом/зашифрованном файле стоит перепроверить.
> Скрипт передаёт содержимое файла через stdin, чтобы путь с пробелами и `%VAR%` не проходил через `cmd.exe` на Windows. Коды возврата соответствуют справке `anydoc --help` версии 0.2.4.

## Протестировано (06.08.2026, песочница Cowork, Node 22, Linux/macOS)

Expand All @@ -132,7 +132,7 @@ bash skills/doc2md/scripts/convert.sh договор.docx
- Несуществующий путь в аргументах — пропускается с понятным сообщением, batch не падает.
- `convert.js` — та же батарея тестов повторена и прошла (рекурсивная папка, коллизия имён, кириллица, вложенная подпапка, missing path).

**Не тестировано вживую:** `.pptx`, `.xlsx`, `.pdf`, `.epub`, боевая пачка документов клиента. **Живой запуск на Windows не делал** — в песочнице нет Windows-окружения; `convert.js` написан без shell-специфичного синтаксиса и с `shell:true` для `npx` на win32, но это обоснованное рассуждение, а не проверка. Проверил формат или ОС — [заведи issue](https://github.com/ilyautov/doc2md/issues), обновлю раздел.
**Не тестировано вживую:** `.pptx`, `.xlsx`, `.pdf`, `.epub`, боевая пачка документов клиента. **Живой запуск новой версии на Windows пока не сделан** — на macOS проверены имена с пробелом и `%TEMP%`, коллизии в `-o`, повреждённый `.docx` и отсутствие значения `-o`. Windows-подтверждение из issue относится к прежнему коду. Проверил новую версию на Windows — [сообщи результат](https://github.com/ilyautov/doc2md/issues).

## Чем отличается от upstream-скилла anydoc

Expand Down
16 changes: 7 additions & 9 deletions skills/doc2md/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,13 @@ node <папка скилла>/scripts/convert.js ~/Downloads/акты/ -o ~/Dow
node <папка скилла>/scripts/convert.js a.pdf b.xlsx "отчёт за март.pptx"
```

На Unix (macOS/Linux/WSL/Git Bash) можно и через bash-версию — поведение идентично:
На Unix (macOS/Linux/WSL/Git Bash) можно вызвать тот же конвертер через bash:

```bash
bash <папка скилла>/scripts/convert.sh договор.docx
```

Без `-o` каждый `<имя>.<расширение>.md` пишется рядом с исходником (например, `отчёт.docx` → `отчёт.docx.md` — расширение сохраняется в имени намеренно, иначе `отчёт.docx` и `отчёт.csv` в одной папке лягут в один и тот же `отчёт.md` и один перезапишет другой). С `-o папка/` все результаты собираются в одном месте.

> ⚠️ При `-o папка/` вывод плоский: два файла с одинаковым именем из разных подпапок (`a/отчёт.docx` и `b/отчёт.docx`) дадут один `отчёт.docx.md`, второй перезапишет первый. Если в дереве возможны тёзки — конвертируй без `-o` (рядом с исходниками) либо по подпапкам отдельными вызовами.
Без `-o` каждый `<имя>.<расширение>.md` пишется рядом с исходником (например, `отчёт.docx` → `отчёт.docx.md`). С `-o папка/` результаты собираются в одном месте. Тёзки из разных подпапок получают суффикс пути, чтобы один результат не перезаписал другой.

Для одного файла и разового вызова можно и напрямую, без скрипта:

Expand All @@ -63,12 +61,12 @@ npx -y @firecrawl/anydoc report.docx -o report.docx.md
## Что скрипт делает, а что нет

- Конвертирует файл(ы), печатает построчный статус (`OK` / `ПРОПУСК` / `ОШИБКА`) и итоговую сводку: сколько успешно, сколько пропущено, сколько ошибок вызова.
- **Различие ПРОПУСК vs ОШИБКА.** `OK` — код возврата anydoc `0`. `ОШИБКА` — не удалось даже запустить `npx`/anydoc (нет в PATH, код `126`/`127`): это отказ окружения, а не «файл нечитаем», и OCR тут не поможет. `ПРОПУСК` — anydoc запустился, но файл не сконвертировался (любой другой ненулевой код): почти всегда скан/шифр/битый файл, в строку выводится stderr от anydoc как есть.
- **Различие ПРОПУСК vs ОШИБКА.** `OK` — код anydoc `0` и результат записан. `ПРОПУСК` — код `3`, PDF нужны OCR-страницы. Любой другой сбой чтения, конвертации, записи или вызова — `ОШИБКА` и ненулевой код всего пакета. В строку выводится stderr от anydoc.
- **Сканы и PDF-картинки без текстового слоя anydoc не читает** — это не баг, а ограничение движка (нет OCR внутри). Такие файлы попадают в «ПРОПУСК», batch на этом не падает. Для них: сначала OCR через скилл `pdf` (шаг «сделать PDF searchable»), потом повторный прогон.
- Зашифрованные/защищённые паролем файлы — туда же, в «ПРОПУСК», с текстом ошибки от anydoc.
- Не удаляет и не трогает исходники. Не перезаписывает существующие `.md`, если явно не совпало имя (тогда перезапишет — как обычная запись файла).
- Зашифрованные/защищённые паролем файлы — `ОШИБКА` с объяснением от anydoc; не отправляй их на OCR.
- Не удаляет и не трогает исходники. Повторный запуск может обновить ранее созданный `.md`.

> Контракт кодов возврата anydoc формально не задокументирован. Скрипт держится консервативной трактовки выше (`0`=OK, `126`/`127`=ошибка окружения, прочее=пропуск). При первом боевом прогоне на заведомо битом/зашифрованном файле стоит перепроверить, что anydoc действительно отдаёт на них ненулевой код, и при необходимости уточнить трактовку.
> Содержимое файла передаётся через stdin, чтобы путь с пробелами и `%VAR%` не попадал в командную строку `cmd.exe` на Windows. Коды возврата взяты из `anydoc --help` версии 0.2.4.

## После конвертации

Expand All @@ -88,7 +86,7 @@ npx -y @firecrawl/anydoc report.docx -o report.docx.md
- `scripts/convert.js` (кросс-платформенная Node-версия): та же батарея тестов повторена и прошла — рекурсивный обход папки, коллизия имён, кириллица в `.docx`/`.csv`, вложенная подпапка, несуществующий путь.
- Синтаксис-гейт обеих версий (`node --check`, `bash -n`) и smoke-тесты (`--help`, несуществующий путь) гоняются в CI на каждый PR.

**Не тестировал:** `.pptx`, `.xlsx`, `.pdf`, `.epub`, реальную пачку документов клиента, файлы за пределами тестовой песочницы. **Живой запуск на Windows не делал** — в песочнице нет Windows-окружения. `convert.js` написан без shell-специфичного синтаксиса и с `shell:true` для `npx` на win32 (известная особенность Node — без этого `npx` на Windows не резолвится), но это рассуждение о корректности, а не проверка. Файлы со спецсимволами `& ^ %` в имени на Windows не проверялись. При первом боевом использовании на Windows — перепроверить и дополнить эту секцию, не выдавать непроверенное за проверенное.
**Не тестировал новую версию на Windows:** нет Windows-окружения. На macOS проверены имена с пробелом и `%TEMP%`, коллизии в `-o`, повреждённый `.docx` и отсутствие значения `-o`. Windows-подтверждение из issue относится к прежнему коду. При первом боевом использовании на Windows — перепроверить и дополнить эту секцию. Также не тестировались `.pptx`, `.xlsx`, `.pdf`, `.epub` и боевая пачка документов клиента.

## Источник

Expand Down
Loading
Loading