* fix(docker): add system ripgrep via apt for keyword search fallback * fix(ci): install ripgrep and npm deps for keyword search in CI * fix(memory-search): warn when ripgrep not resolvable instead of silent skip * fix(memory-doctor): check rg status, arch mismatch, and require errors * test(memory): add keyword search and doctor unit tests * test(memory): unskip e2e keyword tests without RUN_LIVE * docs(handoff): add handoff and ADR for keyword search fix * test(memory): remove unused var in keyword search test * docs(handoff): set PR number to 124 * docs(project-map): update after structural changes (PR#124) --------- Co-authored-by: opencode-agent <agent@opencode.local>
4.6 KiB
4.6 KiB
pr: 124 title: fix(memory): keyword search out-of-box + doctor gaps + tests
Что сделано
- Dockerfile: добавлен
ripgrepвapt-get install(строки 3-16). System rg = fallback;@vscode/ripgrepвnpm install -g(строка 38) остаётся primary path. - ci.yml (job
test): послеsetup-node@v4добавленыapt-get install -y ripgrepиnpm ci(working-directory: .opencode) — CI теперь устанавливает ripgrep и npm-deps для keyword search. - memory-search.ts (~строка 312): при
rgBin===nullпишет warning в stderr (ripgrep not resolvable — keyword search disabled) вместо молчаливого skip. Аналогичный warning в category-fallback блоке. - memory-doctor.ts — закрыты 4 gap'а:
- G9:
checkRipgrepвозвращает{ lines, rgWorks }гдеrgWorks = rgBin !== null && r.status === 0;formatDoctorReportиallGreenиспользуютrgWorks, а неrgBin !== null. - G5:
resolveRgBinary({ allowSystemFallback: true })в execute (консистентно с memory-search.ts:305). - G3: при
rgBin===null(npm-пакет не найден) — строка с подсказкойnpm package missing — run npm ci in .opencode/. - G2:
detectArchMismatch()— если rgBin path содержит 'darwin' приprocess.platform === 'linux'(и обратные комбинации) + arch mismatch (arm64 vs x64) → строкаarch mismatch: binary platform != runtime platformв отчёт.
- G9:
- tests/test_memory_keyword_search.ts (новый): 5 TS unit-тестов для
resolveRgBinary()(npm-package, system-fallback, null-nothing, null-no-fallback) + memory-search stderr warning при rgBin===null. - tests/test_memory_doctor.ts (новый): 4 TS unit-теста — allGreen false при битом бинарнике (G9), allGreen true при рабочем (regression guard), arch-mismatch detection (G2), npm-missing hint в report (G3).
- tests/test_memory_tools_e2e.py: убран глобальный
pytestmarkskipif(RUN_LIVE). Keyword-тестtest_zero_config_keyword_onlyтеперь запускается БЕЗ RUN_LIVE. Semantic-тесты (hybrid, fallback, deletion) имеют individualskipif(not RUN_LIVE).
Проверки: pytest tests/ -x -q 427 passed, 6 skipped; ruff check OK;
ruff format --check OK.
Почему
README заявлял keyword search как "always works", но:
- System
rgне был установлен нигде (Dockerfile/CI/host) — только хрупкий volume-mount npm-пакета. - CI не устанавливал ripgrep ни через apt, ни через npm ci для
.opencode/package.json. memory-searchмолча пропускал keyword search приrgBin===null— без warning, что затрудняло диагностику.memory-doctorимел 4 расхождения: allGreen проверялrgBin!==nullа неr.status===0,allowSystemFallbackрасходился с memory-search, нет arch-mismatch detection, require-ошибки не попадали в отчёт.- E2E-тесты скипались без
RUN_LIVEцеликом — даже keyword-тесты, которые не требуют embeddings API.
Pending
—
Watch out
- TS unit-тесты (
test_memory_keyword_search.ts,test_memory_doctor.ts) runnable underbun test— bun runtime отсутствует на CI host; файлы валидны как TS, но не запускаются pytest'ом. Это тот же pattern чтоtest_commit_tool.ts/test_merge_pr_tool.ts. detectArchMismatch()использует эвристику по имени path (contains 'darwin'/'linux'/'win32' + 'arm64'/'x64') — не вызываетfilecommand. Покрывает основной случай (@vscode/ripgrep platform dir names).resolveRgBinary({ allowSystemFallback: true })в memory-doctor теперь консистентен с memory-search — но меняет поведение: если npm-пакет отсутствует но system rg есть, doctor покажет ✅ вместо ❌. Это намеренно (doctor = зеркало реального поведения search).- CI:
npm ciв.opencode/требуетpackage-lock.json— проверь что он есть в репо (иначе CI упадёт).