opencode-config/docs/handoff/pr-144-optional-badge-subtitle-entrypoint.md
Sergey 0d16b028fa
fix(draw-image): optional badge/subtitle + self-healing docker entrypoint (#144)
* fix(draw-image): conditional slot bg + optional subtitle in buildSvg

* test(draw-image): optional badge/subtitle unit+integration+e2e

* feat(docker): self-healing entrypoint shim + .dockerignore

* test(draw-image): pytest assert --subtitle omitted when absent

* docs(handoff): optional badge/subtitle + docker entrypoint handoff+ADR

* docs(handoff): set PR number 144

* docs(project-map): fix PR refs 143 to 144

---------

Co-authored-by: opencode-agent <agent@opencode.local>
2026-07-30 01:23:25 +03:00

30 lines
No EOL
3.3 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
pr: 144
title: "fix(draw-image): optional badge/subtitle + self-healing docker entrypoint"
---
## Что сделано
Три фикса для draw-image (PR#134 follow-up):
1. **Пустой badge не рисует квадрат**`renderSlotBackground()` перенесён внутрь `if (value)` блока в `buildSvg()` (`.opencode/draw-image/src/render.ts:33-41`). bg/border `<rect>` рендерится ТОЛЬКО если слот заполнен.
2. **Subtitle опционален** — если `args.subtitle` falsy, вся `<text>` строка с `{{subtitle}}` удаляется из шаблона (`render.ts:50-54`). Без subtitle — чистый вывод (только title).
3. **Docker entrypoint (self-healing)** — новый `docker-entrypoint.sh` (корень): проверяет `node_modules/sharp`, при отсутствии `npm ci` (continue-on-error), `exec opencode "$@"`. Dockerfile `ENTRYPOINT``/usr/local/bin/docker-entrypoint.sh`. Новый `.dockerignore` (`app_data/`, `.git`, `**/node_modules`).
Тесты:
- vitest: `render.optional.test.ts` (unit: empty badge → no rect, empty subtitle → no text, filled badge → rect, set subtitle → text), `render.optional.integration.test.ts` (PNG valid with/without subtitle+badge), `e2e.optional.test.ts` (CLI title-only → exit 0, clean SVG).
- pytest: `test_omits_subtitle_flag_when_not_provided` в `tests/test_draw_image_tool.py`.
- Все 55 vitest + 441 pytest зелёные, ruff чист.
Документация: project-map README обновлён (docker-entrypoint.sh, .dockerignore, новые тест-файлы).
## Почему
PR#134 выявил три проблемы: (1) cover без badge рисовал пустой `<rect>` с `fill=#121212` + `stroke=#ccff00` — визуальный мусор; (2) cover без subtitle оставлял пустой `<text>` элемент в DOM; (3) fresh clone + `docker compose up``Cannot find module 'sharp'` (node_modules gitignored, Dockerfile не устанавливал deps). Большинство cover'ов — title-only, нужен чистый вывод.
## Pending
## Watch out
- `docker-entrypoint.sh` использует `#!/bin/sh` (POSIX), не bash — для максимальной портативности в slim-образах. `set -euo pipefail` НЕ используется намеренно: `npm ci` failure не должен рвать entrypoint (continue-on-error pattern).
- `.dockerignore` исключает `**/node_modules` — это означает что `npm ci` в entrypoint ВСЕГДА будет выполняться при первом старте контейнера (node_modules не копируется в образ). Это by design — self-healing.
- `renderSlotBackground` теперь вызывается только для заполненных слотов — если в будущем понадобится bg для пустого слота-плейсхолдера, придется пересмотреть логику.
- Regex `/[^\n]*\{\{subtitle\}\}[^\n]*\n?/g` удаляет всю строку с `{{subtitle}}` — подразумевает что `{{subtitle}}` на отдельной строке в шаблоне (так и есть в cover.svg).