* 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>
3.3 KiB
3.3 KiB
| pr | title |
|---|---|
| 144 | fix(draw-image): optional badge/subtitle + self-healing docker entrypoint |
Что сделано
Три фикса для draw-image (PR#134 follow-up):
- Пустой badge не рисует квадрат —
renderSlotBackground()перенесён внутрьif (value)блока вbuildSvg()(.opencode/draw-image/src/render.ts:33-41). bg/border<rect>рендерится ТОЛЬКО если слот заполнен. - Subtitle опционален — если
args.subtitlefalsy, вся<text>строка с{{subtitle}}удаляется из шаблона (render.ts:50-54). Без subtitle — чистый вывод (только title). - Docker entrypoint (self-healing) — новый
docker-entrypoint.sh(корень): проверяетnode_modules/sharp, при отсутствииnpm ci(continue-on-error),exec opencode "$@". DockerfileENTRYPOINT→/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 cifailure не должен рвать 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).