Интеграция со Starship
Используйте dwe prompt, чтобы выводить компактный, осведомлённый о проекте сегмент внутри промпта Starship.
dwe prompt печатает одну строку для текущего рабочего каталога шелла:
{▪} my-project ✓ ●Полная форма вывода (каждый хвостовой сегмент независимо опционален):
{▪} <проект> [<сервис>] <иконка-деплоя> <иконка-стека>{▪}— логомарка DWE; внутренний квадрат окрашен токеномaccentпроекта изworkspace/styles.yml.<проект>—project.nameизworkspace.yml, с откатом на basename каталога.[<сервис>]— присутствует, когдаcwdнаходится внутри исходного каталога сервиса. Для каждогоworkspace/services/<name>/полеdir:изservice.ymlразрешается относительно корня проекта и сопоставляется сcwd(на вложенных раскладках выигрывает самое глубокое совпадение; если у потомка нет собственногоdir, разворачивается цепочкаextends:). Сервисы, чейdir:указывает на корень проекта (dir: .) или за его пределы (dir: .., абсолютные пути вне корня), молча пропускаются. Рамка из скобок остаётся простой, а внутреннее имя очищается от спецсимволов. На каждый вызов промпта приходится одинos.ReadDirплюс одно небольшое чтение YAML на сервис — это субмиллисекунды на типичных проектах; файлыservice.ymlкрупнее 64 KB на горячем пути пропускаются.<иконка-деплоя>—✓/⟳/⚠/✗, отражает журнал состояния деплоя в.dwe/deploy/state.yml. Опускается, когда состояния деплоя нет.<иконка-стека>—●/◐/○, отражает текущее состояние контейнеров. Опирается на.dwe/prompt-cache.yml(см. Иконка стека). Опускается, когда ни кэш, ни обновление не дали значения.
Стабильность гарантируется только для префикса {▪} <проект> — любой другой хвостовой сегмент может отсутствовать в зависимости от состояния проекта.
Когда шелл находится за пределами любого DWE-проекта, команда завершается с кодом 1 и ничего не печатает — Starship скрывает сегмент через предикат when =.
dwe prompt — это горячий путь для промпта шелла: он полностью обходит cobra, валидацию конфига и lipgloss. Холодный старт на современной машине занимает заметно меньше 50 мс.
Установка
Заголовок раздела «Установка»Добавьте следующий блок в ~/.config/starship.toml:
[custom.dwe]command = "dwe prompt"when = "dwe prompt --check"format = "[$output]($style) "style = "bold"description = "DWE project status"Предикат when = "dwe prompt --check" — молчаливый и работает только по коду возврата: Starship вызывает его раз на промпт, чтобы решить, показывать ли сегмент. Форма command выполняет собственно рендеринг и выводит окрашенный сегмент в stdout.
Кастомизация
Заголовок раздела «Кастомизация»dwe prompt окрашивает только логомарку и иконки — скобки, имя проекта, тег сервиса и окружающие пробелы остаются без цвета. Так всё остальное остаётся свободным для style и format Starship — их можно переоформить, не борясь со встроенным ANSI:
[custom.dwe]command = "dwe prompt"when = "dwe prompt --check"format = "via [$output]($style) "style = "dimmed cyan"Цветовые escape-последовательности внутри сегмента используют \x1b[39m (только цвет переднего плана по умолчанию) — они не сбрасывают окружающие атрибуты.
Иконка деплоя
Заголовок раздела «Иконка деплоя»Вычисляется в этом порядке приоритетов — выигрывает первое совпадение:
| Порядок | Условие | Иконка | Цветовой токен |
|---|---|---|---|
| 1 | деплой status: failed | ✗ | danger |
| 2 | деплой status: partial | ⚠ | warning |
| 3 | есть отложенные изменения (присутствует блок pending) | ⟳ | warning |
| 4 | деплой status: deployed | ✓ | success |
| 5 | нет состояния / not_deployed / ошибка парсинга | (опущена) | — |
Failed и partial идут впереди pending, чтобы промпт первым делом сигнализировал о сломанном состоянии — нужно знать, что что-то не так, прежде чем думать о применении отложенных изменений.
Иконка стека
Заголовок раздела «Иконка стека»Иконка стека отражает текущее состояние Docker-контейнеров. Она не зависит от иконки деплоя — проект может показывать ✓ ○ (деплой успешен, контейнеры остановлены вручную).
| Состояние | Глиф | Цветовой токен | Смысл |
|---|---|---|---|
| running | ● | success | все ожидаемые контейнеры подняты |
| partial | ◐ | warning | часть контейнеров поднята, часть остановлена |
| stopped | ○ | muted (по умолчанию для промпта #6B7280; переопределяется через colors.muted в workspace/styles.yml) | ни один контейнер не работает |
| (нет) | — | — | кэша нет, и обновление не дало пригодного значения |
Состояние читается из stale-while-revalidate-кэша в .dwe/prompt-cache.yml:
updated_at: 2026-06-03T12:34:56Z # RFC3339 UTCstate: running # running | partial | stopped- TTL: 2 минуты. Чтение свежего кэша — это чистый файловый ввод-вывод, без
docker ps. - Устарел или отсутствует: промпт вызывает
docker ps -q --filter label=com.docker.compose.project=<project>с жёстким тайм-аутом 150 мс. Probe применяет переопределенияprocess_envизworkspace/docker.yml/docker.local.yml(например,DOCKER_HOST,DOCKER_CONTEXT), поэтому обращается к тому же демону, что и lifecycle-команды. По тайм-ауту или при любой ошибке запись в кэш не выполняется. - Потолок доверия к устаревшему значению: 10 минут (5× TTL). Устаревшее закэшированное значение переживает подтверждённый нулевой результат обновления только в пределах потолка; дальше промпт отображает
stopped(по-прежнему не записывая кэш), поэтому стек, остановленный в обход dwe, сходится к○, а не показывает●бесконечно. Неподтверждённый ноль (ошибка docker / тайм-аут) не понижает состояние ни при каком возрасте. - Атомарная запись: временный файл + rename в том же каталоге, поэтому параллельные промпты не могут повредить файл.
Кто пишет в кэш
Заголовок раздела «Кто пишет в кэш»Разные места знают про стек разное. Каждое выбирает самое безопасное действие — пишет, когда уверено, инвалидирует, когда область ограничена, и никогда не врёт:
| Место | Действие |
|---|---|
dwe run | пишет running |
dwe restart (без аргумента-сервиса) | пишет running |
dwe restart <service> | инвалидирует (удаляет файл кэша) |
dwe stop (без --service) | пишет stopped |
dwe stop <service> | инвалидирует |
dwe deploy run (без --service) | инвалидирует (деплой может оказаться no-op из-за «already up-to-date») |
dwe deploy run --service <n> | инвалидирует |
dwe reset run (полная остановка проекта) | пишет stopped |
dwe reset run --service <n> | инвалидирует |
dwe services enable/disable --apply | пишет running (после того как весь план переключения, включая after-хуки, завершён) |
dwe status (верхнего уровня) | пишет точный агрегированный Health (running/partial/stopped) |
dwe status <subcommand> | не пишет (область ограничена секцией) |
dwe snapshot restore / rollback | инвалидирует (состояние после restore произвольное) |
dwe prompt (синхронное обновление) | пишет running, если docker ps вернул > 0 — никогда stopped |
Правило no-downgrade при prompt refresh
Заголовок раздела «Правило no-downgrade при prompt refresh»Собственное синхронное обновление dwe prompt пишет только running. Нулевой результат docker ps невозможно отличить между двумя случаями:
- стек действительно остановлен, либо
- фильтр по лейблу неправильный (шаблонизированный
docker.yml.project_nameпромптом не загружается — см. Известные ограничения).
Разрешить обновлению из промпта писать stopped означало бы либо (а) понизить корректный running, оставленный авторитетным источником (lifecycle / status), либо (б) записать неверный stopped в отсутствующий кэш после инвалидации. Закрепление записи stopped только за авторитетными источниками сохраняет честность кэша.
Правило ограничивает запись, а не отображение: когда закэшированное значение старше 10-минутного потолка доверия, подтверждённый нулевой результат обновления отображает иконку как stopped для этого промпта (файл кэша по-прежнему не трогается). В пределах потолка побеждает устаревшее значение — это не даёт нулю от неправильного лейбла «моргать» иконкой здорового стека.
Запись в кэш везде выполняется по принципу best-effort: ни обновление из промпта, ни lifecycle-команды не падают при ошибках ввода-вывода. Кэш — это про наблюдаемость, а не про корректность.
Поведение в терминалах без цвета
Заголовок раздела «Поведение в терминалах без цвета»dwe prompt следует спецификации NO_COLOR: если переменная окружения NO_COLOR установлена в любое значение (включая пустую строку), все ANSI-escape-последовательности подавляются и вывод состоит только из обычных символов.
{▪} my-project ✓ ●Известные ограничения
Заголовок раздела «Известные ограничения»- Автоопределение светлой/тёмной темы: промпт всегда использует тёмный вариант палитры. Большинство терминалов тёмные; поддержку светлых можно добавить позже через
COLORFGBG, если будет спрос. - Нет флага
-c:dwe promptвсегда поднимается вверх от$PWD. Это намеренно — промпт шелла отражает текущий каталог шелла, а не произвольный указатель на проект. - Свой бинарник docker: указание
binary_docker = podman(или абсолютного пути) в~/.config/dwe/config(или любое не-dockerзначение) обходит обновление, инициированное промптом —shared/promptжёстко зашивает имя бинарникаdockerна горячем пути. Переопределенияprocess_env(DOCKER_HOST,DOCKER_CONTEXT, …) к probe применяются, так что конфигурации с несколькими демонами работают; зафиксировано только имя бинарника. Lifecycle-команды иdwe statusпо-прежнему пишут кэш с правильным бинарником, так что при активной работе иконка остаётся точной; вхолостую не выполняется только 2-минутное обновление. - Шаблонизированное имя compose-проекта: проекты, у которых
workspace/docker.ymlзадаётproject_nameшаблоном (например,${project.prefix}_${project.name}), при обновлении из промпта получат отdocker psноль строк —shared/promptчитает только литеральныйproject_nameи для шаблонных значений откатывается наprefix-name. В сочетании с правилом no-downgrade обновление из промпта ничего не пишет — иконка остаётся корректной, пока lifecycle-команды иdwe status(которые знают настоящее compose-имя) держат кэш свежее 10-минутного потолка доверия. За потолком постоянный нулевой результат отображает○даже для работающего стека до следующей авторитетной записи; если это мешает, задайте литеральныйproject_name(например, вworkspace/docker.local.yml). - Ручной
docker stopвне dwe: кэш обновлением из промпта не перезаписывается (правило no-downgrade), поэтому иконка показывает устаревшее состояние до 10-минутного потолка доверия; после него подтверждённый нулевой результат отображает○на каждом промпте. Запуститеdwe status, чтобы обновить закэшированное состояние немедленно. - Сервисы без
dir:: tool/infra-сервисы (и любое приложение без примонтированных исходников) никогда не появляются как[<сервис>]в промпте — у них нет каталога исходников, внутри которого мог бы находитьсяcwd. Проект, деплой и стек промпт при этом рендерит как обычно. - Пути через симлинки:
dwe promptне вызываетfilepath.EvalSymlinksни дляcwd, ни для разрешённогоdir:. Если доcwdдобрались через симлинк, аdir:указывает на канонический путь (или наоборот), тег сервиса молча исчезает. Чтобы избежать сюрпризов, используйте вdir:изservice.ymlреальные пути. - Кавычки в разных шеллах: sh, bash и zsh принимают строки
command/whenкак есть. Пользователям fish может потребоваться скорректировать кавычки вstarship.toml, если их конфиг Starship оборачивает команды иначе.
До / после
Заголовок раздела «До / после»Без сегмента:
~/code/my-project ❯С сегментом (корень проекта):
{▪} my-project ✓ ● ~/code/my-project ❯С сегментом (внутри исходного каталога сервиса api — при условии, что в workspace/services/api/service.yml задано dir: ./services/api):
{▪} my-project [api] ✓ ● ~/code/my-project/services/api ❯(Логомарка DWE и иконки окрашены в реальных терминалах.)