* feat(memory): wire setup-memory.sh to Python CLI + JS wrapper * test(memory): add wrapper generation, idempotency, backup tests * docs(memory): update project map for setup-memory wrapper integration * docs(handoff): add handoff and ADR-033 for plugin wiring * docs(handoff): set PR number * docs(handoff): fix Pending em-dash typo in PR#77 handoff --------- Co-authored-by: opencode-agent <agent@opencode.local>
6.4 KiB
| pr | title |
|---|---|
| 77 | Wire memory CLI into opencode-memory plugin via setup-memory.sh wrapper |
Что сделано
.opencode/scripts/setup-memory.sh: добавленаWRAPPER_PATHenv-переменная (default/usr/local/lib/node_modules/@mathew-cf/opencode-memory/node_modules/@mathew-cf/rag-cli/bin/rag.js, override черезMEMORY_WRAPPER_PATH)..opencode/scripts/setup-memory.sh: добавлен выбор Python-интерпретатораMEMORY_PYTHON— prefer${OPENCODE_WORKSPACE}/.venv/bin/python, then.venv/bin/python, thenpython3(override черезMEMORY_WRAPPER_PYTHON). Причина: systempython3не имеетhttpx(нет venv), CLI падает на import — wrapper должен вызывать venv-python..opencode/scripts/setup-memory.shшаг 5:command -v rag→"$MEMORY_PYTHON" -c "import src.memory". Если доступен →python -m src.memory index "$MEMORY_DIR" -o "$MEMORY_DIR/.rag". Если нет → echo skip + continue (best-effort, не exit 1)..opencode/scripts/setup-memory.shшаг 5b (новый): генерация JS wrapper для плагина@mathew-cf/opencode-memory. Wrapper содержитspawnSync(py, ["-m", "src.memory", ...process.argv.slice(2)], { cwd: OPENCODE_WORKSPACE })— делегируетrag index/search/downloadв Python memory CLI. Idempotent черезcmp -s(сравнение контента, НЕ$(cat)— bash$()удаляет trailing newline, давал false-negative). Backup.origоригинала один раз (не перезаписывается).chmod +x.tests/test_setup_memory.py:_run_scriptрасширенwrapper: Path | Noneпараметром →MEMORY_WRAPPER_PATHenv override. Все существующие тесты обновлены передаватьwrapper=tmp_path/"wrapper"/"rag.js"(герметичность — не пишут в/usr/local/lib/...). insteadOf-тесты (прямыеsubprocess.run) тоже обновлены. mypy type-args починены (CompletedProcess[str],dict[str, str | None]).tests/test_setup_memory.py: +4 новых теста —test_wrapper_generated(wrapper существует + executable),test_wrapper_idempotent(2 запуска → контент идентичен + "wrapper correct"),test_wrapper_content(содержитpython,-m,src.memory,spawnSync,process.argv.slice),test_wrapper_backup_original(.origсохраняет старый контент, НЕ перезаписывается при 2-й замене).docs/project-map/README.md: setup-memory.sh entry обновлён (6-step → 7-step, +JS wrapper), test_setup_memory.py entry обновлён (+wrapper gen/backup).- ADR-033 + этот handoff.
Почему
PR #75 (merged) отрефакторил Memory CLI (second-brain → memory, OpenAI env, chunking, batching, dedup), но плагин @mathew-cf/opencode-memory всё ещё вызывал родной Rust @mathew-cf/rag-cli — 5-10 мин на 1.2 MB на CPU, 3 зомби-процесса зафиксировано, индекс никогда не записан ($OPENCODE_MEMORY_DIR/.rag отсутствовал). Плагин находит rag через require.resolve("@mathew-cf/rag-cli/bin/rag.js") (вендорный dist/index.js:12703-12708, НЕ патчим).
Решение: setup-memory.sh генерирует JS wrapper по пути, который резолвит плагин. Wrapper = прагматичный shim (аналог pyenv/nvm shims), перехватывает require.resolve → перенаправляет вызовы в Python memory CLI. Идемпотентен (content check через cmp -s), backup .orig оригинала один раз. PR #2 в серии из 2 (после PR #75).
Отклонение от спеки: спека говорила spawnSync("python3", ["-m", "src.memory", ...]) — но system python3 не имеет httpx (нет venv), CLI падает на import. Реализация выбирает venv-python (${OPENCODE_WORKSPACE}/.venv/bin/python → .venv/bin/python → python3), wrapper встраивает выбранный путь. Зафиксировано в ADR-033 Альтернативы.
Pending
—
Watch out
$(cat)vscmp -sдля idempotency. Bash$()удаляет trailing newlines —$(cat file)возвращает контент без\nв конце, а$VAR(одиночные кавычки) содержит\nперед закрывающей'. Сравнение[ "$(cat)" = "$VAR" ]= false даже при идентичном контенте. Решение:cmp -s "$WRAPPER_PATH" /dev/stdin <<<"$WRAPPER_CONTENT"— байт-точное сравнение. НЕ возвращаться к$(cat).- Wrapper встраивает абсолютный путь к Python.
MEMORY_PYTHONразрешается на момент запуска setup-memory.sh и встраивается в wrapper как literal string. Если venv переедет — wrapper нужно перегенерировать (удалить wrapper, запустить setup-memory.sh). Альтернатива (читать env в runtime черезprocess.env.MEMORY_WRAPPER_PYTHON) — оставлена как override, но default встраивается для надёжности (env может быть не set в контексте плагина). MEMORY_WRAPPER_PATHenv override обязателен для тестов. Без него скрипт пишет в/usr/local/lib/node_modules/@mathew-cf/opencode-memory/...— real plugin path. Все тесты передаютwrapper=tmp_path/"wrapper"/"rag.js". Smoke-test может использовать real path (если плагин установлен).- Smoke-test пройден (2026-07-26):
bash .opencode/scripts/setup-memory.shсMEMORY_WRAPPER_PATH=/tmp/...→ wrapper сгенерирован,.rag/index.jsonсоздан через облако (1 файл, ~42KB), idempotency подтверждена (2-й запуск → "wrapper correct"), backup.origработает. Реальный plugin path НЕ тестировался (плагин может быть не установлен в тестовом окружении).