6.0 KiB
WALKTHROUGH — Email Assistant (капитанский журнал)
Воспроизводимость: хронология, команды, решения, ошибки и как чинили.
2026-09-11
Фаза 1.7: динамическое обнаружение подпапок INBOX
Проблема: mail_archive.py хардкодил 18 подпапок INBOX, на сервере их 136+.
Решение в mail_archive.py:
get_inbox_subfolders()— парситhimalaya folder list(таблица ASCII), фильтруетINBOX/, поддерживает глубину 3, fallback на хардкод при ошибке.--all=FOLDERS + get_inbox_subfolders()→ 140 папок.run_cmd()— добавленtry/except FileNotFoundError(himalaya не в PATH).- Таймаут envelope list поднят 60 → 180с: INBOX (14k писем) перечислялась >60с.
Проверено:
get_inbox_subfolders()→ 136 папок, 120 глубоких.--folder "INBOX/!Реестр платежей/Акты" --limit 10 --drain— работает.--folder "INBOX/!Завки/Либра" --limit 5 --drain— 4 письма, OK.- Smoke
--allс заглушкой archive_folder — 140 папок в списке. - Fallback (HIMALAYA_CMD=несуществующий) — работает.
Зависание --all: envelope list на большой INBOX висел >60с (таймаут).
Поднятие до 180с + --drain (предохранитель 10k проходов) решило. Крон-обёртка
mail-archive.sh переведена на --all --drain + HOME=/home/estorozhenko
(himalaya не находил конфиг из-за смены HOME).
Git: c7430d1 «feat: динамическое обнаружение подпапок INBOX (Фаза 1.7)».
Анализ Nylas CLI → отклонено
Задача: пользователь спросил, упростит ли Nylas получение/отправку писем.
Вывод: Nylas — облачный SaaS (api.us.nylas.com), не локальный CLI. Письма идут через серверы Nylas; платная подписка; IMAP-гранты гибнут при ротации пароля; Contacts API для generic IMAP платный. Для корпоративного IMAP + локального архива — не подходит.
Artifacts: NYLAS_ANALYSIS.md + ссылка в README. Git: d4bf3ed.
Задача 4: Анализ ФС vs Maildir → закрыт
Задача: оценить, удобен ли формат email.md (ФС) vs Maildir/MBOX/notmuch,
учитывая мотивацию — локальная LLM в скриптах без облака.
Реальные данные (замер): 4884 email.md, 76 МБ; INBOX 2674 (вкл. 1224 в 2026/), Archive 876, Отправленные 790, Sent 544; контактов 81 (а не 5!).
Вывод (STORAGE_ANALYSIS.md): остаться на email.md — он идеален для
LLM-скриптов (cat email.md | ollama run qwen3:8b), человекочитаем, атомарен
(папка UID на письмо). Maildir даёт стандартность, но raw-MIME (нужен парсер),
нечитаемые имена, НЕТ тэгов. Эволюция: tags: [] в frontmatter + опц. экспорт
в Maildir + FTS5 остаётся.
OpenSpec: change email-storage-analysis (3 требования) → validate → archive
(delta → openspec/specs/email-storage-format/spec.md). Git e31b5f2.
Портфель: веб-UI + календарь/задачи (ПЛАН)
PLAN_WEBUI.md — 7 задач, порядок 4→2→3→1→6→7. Решения пользователя:
- Трекер задач и календаря НЕТ → добавлять как отдельные сервисы.
- Все сервисы — в отдельных Docker-контейнерах.
- Стек: Radicale (CalDAV) + Vikunja (трекер).
Задача 2: Radicale (docker) — развёрнут частично
Сделано:
/opt/hermes/email-assistant/radicale/docker-compose.yml(образkozea/radicale, порт 5232).- Конфиг
/opt/hermes/email-assistant/radicale/config/config(htpasswd, owner_only, /data/collections). - Пользователь
estorozhenko—htpasswd -c -b -m data/users estorozhenko <pass>(пароль в/opt/hermes/email-assistant/radicale/.env,RADICALE_PASS). docker compose up -d→ контейнерradicaleработает.
Проверено: curl -X PROPFIND http://127.0.0.1:5232/ -u estorozhenko:PASS → 207;
без пароля → 401 ✅. Radicale 3.8.1.dev0, слушает 0.0.0.0:5232.
Ошибка/урок: command: ["radicale", "-C", ...] падал unrecognized arguments: radicale — entrypoint образа УЖЕ вызывает radicale, передавать только флаги:
command: ["-C", "/config/config"].
Заблокировано: создание коллекций. MKCOL /Личный/ → 403. Radicale 3.x
создаёт коллекции иначе (PUT ресурса с Content-Type: text/calendar в новую
коллекцию). Попытка проверки через PUT тестового VEVENT была заблокирована
таймаутом команды (execution guard) — жду решение пользователя/возобновление.
Осталось (Задача 2): коллекции (Личный/Рабочий/Задачи), Vikunja (:3456, postgres), Caddy (cal.nixg.ru, tasks.nixg.ru), Android.
Известные открытые хвосты (репозиторий)
PLAN_WEBUI.md— untracked (не закоммичен).- Cron mail-index-incremental и digest-weekly — не настроены.
- Push mirror gitea → gitverse — не настроен (нужен токен [REDACTED]).