Уведомления
Нативные desktop-уведомления, срабатывающие при завершении долгих операций DWE (успех или провал). Уведомления — это пользовательская забота: настройки лежат в файле пользовательского конфига вне проекта (с опциональным переопределением на уровне проекта), а не в workspace.yml.
См. также: Локализация (i18n) — про перевод описаний пользовательских команд и UI-строк.
Содержание
Заголовок раздела «Содержание»- Когда срабатывают уведомления
- Расположение файлов
- Синтаксис конфигурации
- Ключи (MVP)
- Переменные окружения
- Матрица условий
- Определение неинтерактивности
- Политика drop-on-busy
- Пример конфигурации
- Формат заголовка и тела
- Иконка и имя приложения на macOS
Когда срабатывают уведомления
Заголовок раздела «Когда срабатывают уведомления»| Операция | Срабатывает? | Условие на операцию |
|---|---|---|
dwe deploy | да | notify_deploy_enabled |
dwe run | да | notify_run_enabled |
dwe restart | нет (внутренняя фаза run подавлена через SkipNotify) | — |
dwe stop | нет | — |
dwe reset | нет | — |
dwe commands <id> (top-level, с notify: true на CommandDef) | да | notify_commands_enabled |
dwe commands <id> (без notify: true) | нет | — |
| Под-шаг workflow (последовательный или параллельный) | нет — всегда подавляется в рантайме независимо от собственного поля notify: | — |
| Действие пайплайна деплоя, вызывающее команду | нет — то же правило | — |
Daemon-команды (.start / .logs / .stop / .restart) | notify: true отвергается на этапе валидации | — |
Правило: уведомление срабатывает для команды, которую вы набрали, а не для любой команды, которую она запускает внутри. У команды, помеченной notify: true и вызванной транзитивно (под-шаг workflow или действие пайплайна), уведомление подавляется рантайм-проверкой SkipNotify.
Валидатор выдаёт info-диагностику, когда может статически обнаружить команду с notify: true, помещённую прямым под-шагом внутри блока parallel: — чисто как раннее предупреждение. Реальное подавление происходит в рантайме и покрывает транзитивные случаи, которые валидатор не видит.
Подавление на один вызов через --silent
Заголовок раздела «Подавление на один вызов через --silent»Каждая команда, способная вызвать уведомление, принимает флаг --silent, который подавляет desktop-уведомление для этого одного вызова. Полезно для скриптовых / CI-запусков, где пользователя нет за рабочим местом и он не увидит попап.
Флаг доступен у: dwe deploy run, dwe run, dwe snapshot create, dwe snapshot restore, dwe snapshot rollback, dwe snapshot remove и dwe commands <id>. Это разовое переопределение — пользовательский конфиг и условия на операцию не меняются.
Расположение файлов
Заголовок раздела «Расположение файлов»Два файла читаются в следующем порядке приоритета (ниже → выше):
-
Глобальный пользовательский конфиг в
~/.config/dwe/configна каждой ОС (Linux, macOS, Windows). Никакого нативного для платформы расположения, никакого XDG-отката — один путь везде. Отсутствие файла молча трактуется как пустота. Если DWE когда-нибудь его пишет, режим —0600. -
Переопределение на уровне проекта в
<project>/.dwe/config. Директория.dwe/уже игнорируется DWE через gitignore. Отсутствие файла молча трактуется как пустота. -
Переменные окружения переопределяют оба файла (высший приоритет).
Ошибка разбора в любом из файлов всплывает наружу и отключает уведомления для этого запуска (предупреждение логируется через slog); сама операция никогда не блокируется подсистемой уведомлений.
Синтаксис конфигурации
Заголовок раздела «Синтаксис конфигурации»Плоские строки key = value:
- Только
#-комментарии на всю строку — inline#-комментарии вызывают ошибку разбора. - Пустые строки игнорируются.
- Ключи используют строчные буквы, цифры и подчёркивания; точечные ключи отвергаются (
notify_telegram_token, неnotify.telegram.token). - Булевы:
true/false. - Списки: через запятую.
- Неизвестные ключи — предупреждения, а не ошибки.
Ключи (MVP)
Заголовок раздела «Ключи (MVP)»| Ключ | Тип | По умолчанию | Назначение |
|---|---|---|---|
notify_enabled | bool | true | Главный выключатель — когда false, ни одно уведомление не срабатывает |
notify_run_enabled | bool | true | Гейт для dwe run |
notify_deploy_enabled | bool | true | Гейт для dwe deploy |
notify_commands_enabled | bool | true | Гейт для пользовательских команд с notify: true |
notify_channels | list | native | Список backend-имён через запятую; в MVP подключён только native |
Переменные окружения
Заголовок раздела «Переменные окружения»Каждый ключ имеет соответствующую env-переменную DWE_<UPPER_SNAKE>, которая переопределяет всё, что задано в файлах:
| Env-переменная | Переопределяет |
|---|---|
DWE_NOTIFY_ENABLED | notify_enabled |
DWE_NOTIFY_RUN_ENABLED | notify_run_enabled |
DWE_NOTIFY_DEPLOY_ENABLED | notify_deploy_enabled |
DWE_NOTIFY_COMMANDS_ENABLED | notify_commands_enabled |
DWE_NOTIFY_CHANNELS | notify_channels |
Булевы env-значения: 1 / true / yes — истинные; 0 / false / no — ложные.
Матрица условий
Заголовок раздела «Матрица условий»Уведомление срабатывает, только если все следующие условия истинны:
notify_enabled = true(главный выключатель).- Соответствующий per-op ключ равен
true(notify_deploy_enabled,notify_run_enabledилиnotify_commands_enabled). notify_channelsнепуст и содержит хотя бы один известный backend (nativeв MVP).- Окружение интерактивное (см. следующую секцию).
- Для
dwe commands:CommandDefимеетnotify: trueи команда — top-level вызов (SkipNotify == false).
Любой промах → молчаливый no-op.
Определение неинтерактивности
Заголовок раздела «Определение неинтерактивности»Уведомления короткозамыкаются, когда верно любое из:
- Переменная окружения
CIзадана в любое непустое значение. DWE_NONINTERACTIVEзадан ровно в1илиtrue(чувствительно к регистру;TRUE/True/YESНЕ отключают).stdinне подключён к терминалу (stdout намеренно не проверяется — пайп вывода с сохранённым интерактивным stdin — это ровно тот сценарий, где пассивное toast-уведомление наиболее ценно).
Это означает, что CI-запуски, piped-вывод и скриптовые вызовы никогда не порождают desktop-уведомление, независимо от конфига.
Политика drop-on-busy
Заголовок раздела «Политика drop-on-busy»Нативный backend ограничен одним уведомлением одновременно на CLI-процесс. Если демон ОС-нотификатора зависает на предыдущем уведомлении (редко, но наблюдалось на некоторых Linux-сетапах), последующие уведомления внутри этой операции молча отбрасываются и логируются на debug-уровне. Backend применяет внутренний 2-секундный таймаут; вызывающая операция никогда не задерживается в ожидании нотификатора.
Особенности платформ
Заголовок раздела «Особенности платформ»macOS использует terminal-notifier, когда он есть в PATH (установка через brew install terminal-notifier), и откатывается на osascript в противном случае. Логотип DWE передаётся как -contentImage, чтобы он рендерился как thumbnail внутри карточки уведомления — современный macOS пин’ит маленький слот app-иконки на bundle-иконку самого terminal-notifier и молча игнорирует override’ы -appIcon. Откат на osascript вообще не может нести кастомную иконку и показывает иконку Script Editor.
Если на macOS уведомления перестают появляться как баннеры, несмотря на то что terminal-notifier -list DWE показывает их как доставленные, демон Notification Center на macOS застрял. Чинится так:
killall NotificationCenterLinux использует libnotify через dbus (или notify-send как откат); иконка проходит напрямую как PNG-payload.
Windows использует нативные toast-уведомления со встроенным PNG.
Пример конфигурации
Заголовок раздела «Пример конфигурации»Типичная настройка: уведомлять о деплое и ad-hoc командах, но молчать про inner-loop цикл dwe run.
# ~/.config/dwe/config (одинаково на каждой ОС)
notify_enabled = truenotify_deploy_enabled = truenotify_run_enabled = false # тихо во время inner-loop разработкиnotify_commands_enabled = truenotify_channels = nativeЗаглушить всё глобально, не трогая per-op флаги:
notify_enabled = falseЗаглушить только для одного проекта (per-project override в <project>/.dwe/config):
notify_run_enabled = falseФормат заголовка и тела
Заголовок раздела «Формат заголовка и тела»Нативный backend рендерит фиксированный, брендированный формат. Имя проекта (когда известно) появляется в заголовке; тело несёт тайминг и, при провале, однострочное усечённое сообщение об ошибке.
| Исход | Заголовок | Тело |
|---|---|---|
| Успех | ✓ DWE · <project>: <op> succeeded | <duration> |
| Провал | ✗ DWE · <project>: <op> failed | <duration> + (с новой строки) усечённое сообщение об ошибке |
Когда у события нет связанного проекта (редко — обычно только синтетические тестовые события), сегмент · <project> опускается и заголовок схлопывается в ✓ DWE: <op> succeeded / ✗ DWE: <op> failed.
Примеры:
✓ DWE · acme-api: deploy succeeded1m 42s✗ DWE · acme-api: run failed3.2sexit status 1: migration aborted: relation "users" does not existСообщения об ошибках обрезаются до первой строки и усекаются до 200 рун (хвостовое … означает усечение). Корзины форматирования длительности: <1s → Xms, <60s → X.Xs, <1h → Xm Ys, ≥1h → Xh Ym.
Иконка и имя приложения на macOS
Заголовок раздела «Иконка и имя приложения на macOS»На macOS иконка DWE и имя приложения DWE в баннере уведомления требуют установленного terminal-notifier:
brew install terminal-notifierКогда terminal-notifier присутствует, beeep делегирует ему, и встроенная иконка DWE и AppName = "DWE" соблюдаются.
Без него beeep откатывается на AppleScript (osascript), который в свежих релизах macOS показывает отправителя как Script Editor и игнорирует иконку. Функциональность не страдает — деградирует только визуальное представление. Текст заголовка (который и так несёт префикс DWE · <project>) остаётся правильным в любом пути.
Linux (libnotify) и Windows (toast) соблюдают встроенную иконку и имя приложения без дополнительной настройки.