| name | romanian-anki |
| description | Use whenever the user sends Romanian or Ukrainian words to add to the Anki deck "Limba românǎ". Triggers on any message that looks like a single word/phrase, a list of words, a screenshot with foreign text, or explicit requests like "додай", "внеси в колоду", "додай в anki", "нове слово". Handles full pipeline — dexonline lookup (via scripts/dex_lookup.py, NOT WebFetch), double-check, table preview, user approval, backup, AnkiConnect call, history logging, git commit. Do NOT trigger when the user is clearly asking about infrastructure, debugging, or code edits unrelated to adding words. |
Romanian → Anki word-adder
Формат картки і project-level факти — в ../../../CLAUDE.md. Цей скіл — про як виконати додавання.
Три залізних правила
-
Не WebFetch для dexonline. Він обробляє сторінку маленькою моделлю, яка губить <span class="tonic-accent"> і дає невірний наголос. Завжди scripts/dex_lookup.py.
-
Gate: прогін тестів парсера перед першим dex_lookup.py у сесії і ще раз перед add_notes.sh.
./scripts/run_tests.sh
Не OK — зупинись. Діагностика: (a) який test_* упав, (b) ./tests/fixtures/refresh.sh <слово> і звіряння HTML з парсером, (c) фіксити парсер + додати тест на зламаний case. Без зеленого — не парсити, не додавати.
-
НІКОЛИ не видаляй нотатки без явного дозволу. Колода синкається на кілька девайсів; видалення на одному не гарантовано пошириться (інший девайс, що не синкався з моменту видалення, поверне нотатку назад при наступному sync). Замість видалення — suspend (action suspend через AnkiConnect, або через cardsInfo → suspend cards by id). Suspend синкається коректно. Дублі і непотрібні картки → suspend, не delete. Дозвіл на delete — тільки явним «можеш видалити», не загальним «розберись».
Пайплайн
1. Зрозуміти вхід
- Яка мова кожного слова (рум / укр).
- Укр → підбери румунський еквівалент спершу.
- Якщо значення неоднозначне (напр. "замок" = building vs. lock) — спитай.
2. Парсинг dexonline
З кореня проєкту:
python3 scripts/dex_lookup.py <слово1> <слово2> ...
JSON-масив з полями: pos, gender, article, plural_numeral, stressed_singular, stressed_plural, candidate_fronts, all_stressed_forms, url, error.
3. ПОВТОРНА перевірка — критично
Виклич скрипт другий раз з тими самими словами. Порівняй stressed_singular, stressed_plural, pos, gender. Відмінність = нестабільність → покажи користувачу обидва варіанти, не продовжуй мовчки.
python3 scripts/dex_lookup.py <слова> > /tmp/dex1.json
python3 scripts/dex_lookup.py <слова> > /tmp/dex2.json
diff /tmp/dex1.json /tmp/dex2.json
Чому двічі: DEX іноді віддає кешовану чи неповну відповідь; одне співпадіння — випадковість, два — сигнал.
4. Front
База — candidate_fronts[0] (скрипт уже застосовує артиклі, числівники, наголос за формулами з CLAUDE.md).
Уточнення:
- Іменник у конкретному контексті → додай
de {контекст} у кінці (o fo<u>a</u>rfecă (două fo<u>a</u>rfeci) de manichiură).
pos=null або порожні candidate_fronts → вибери з all_stressed_forms вручну і повідом користувача.
5. Back (укр)
Основний переклад. Додаткові значення через кому. Уточнення/контекст — <br>(…) або (…) в кінці.
Приклад: спека<br>(коли влітку у школярів).
6. Таблиця перед додаванням
| # | Front (ром) | Back (укр) | Частина мови | DEX |
|---|---|---|---|---|
| 1 | o fo<u>a</u>rfecă (două fo<u>a</u>rfeci) de manichiură | манікюрні ножиці | іменник, ж.р. | [посилання](https://dexonline.ro/definitie/foarfec%C4%83) |
Скажи: "Дай відмашку — додаю."
7. Підтвердження
"ок" / "додавай" / "так" → крок 8. Правки → перероби таблицю. Скасування → стоп.
Ніколи не додавай без явного ОК.
8. Додавання в Anki
./scripts/run_tests.sh
./scripts/backup.sh "before-<короткий-опис>"
./scripts/add_notes.sh /tmp/anki_batch.json
Вихід має бути Додано: N/N. Якщо 0/N — ймовірно, дубль (AnkiConnect повертає null для існуючих нотаток; повідом, не падай).
9. Історія
У added-words.md — новий розділ:
## 2026-04-17 14:30
- `o fo<u>a</u>rfecă (două fo<u>a</u>rfeci) de manichiură` → манікюрні ножиці
Дата: date +"%Y-%m-%d %H:%M". Групуй під існуючим заголовком, якщо той самий день.
10. Git-коміт
cd "$(git rev-parse --show-toplevel)"
git add added-words.md
git commit -m "Add: <слово1>, <слово2>, …"
.apkg не комітяться (.gitignore).
Troubleshooting
Нове слово дає дивний результат (порожній plural, неправильний рід, криво визначений наголос):
./tests/fixtures/refresh.sh <слово> — скачати HTML.
- Додати слово в
tests/fixtures/_words.txt + golden-запис у tests/fixtures/expected.json.
./scripts/run_tests.sh → якщо падає, фіксити парсер. Цикл: write test → run → fix → run → pass.
- Тільки потім додавати в колоду.
Sanity-перевірки:
curl -s -X POST http://127.0.0.1:8765 -d '{"action":"version","version":6}'
./scripts/run_tests.sh --live
python3 scripts/dex_lookup.py timp
Пастки, які легко зачепити:
- HTML в Anki — сирий (
<u>, <br>), не екрануй через <.
- Діакритики
ă ș ț î â — копіюй з DEX (скрипт повертає правильно); НЕ переписуй з пам'яті.
Кодування: ǎ → ă (caron vs breve)
У Front нових карток використовуй тільки ă (a-breve, U+0103) — справжній румунський символ. Ніколи не пиши ǎ (a-caron, U+01CE) — це артефакт Claude Desktop при копіюванні рум. тексту/скріншотів. Те саме для великої літери: Ă (breve), не Ǎ (caron).
Якщо у вхідному повідомленні від користувача (скрін, транскрипт) бачиш ǎ — мовчки нормалізуй до ă перед парсингом і додаванням. Не показуй це як два різні слова, не обговорюй — просто заміни.
Швидка перевірка одного слова в JSON-batch перед add_notes.sh:
grep -n 'ǎ\|Ǎ' /tmp/anki_batch.json && echo "WARN: caron у Front — нормалізуй на breve"
Виняток: назва колоди Limba românǎ зберігається з caron — історично і зашита в scripts/add_notes.sh:11. Її не чіпаємо.