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

3.3 KiB
Raw Blame History

pr title
144 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 upCannot 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).