# ADR-022 (PR 53): Persist git insteadOf helper for GITHUB_TOKEN in setup-memory.sh

## Статус
Accepted (2026-07-24)

## Контекст

При миграции opencode-config на linux-1 `setup-memory.sh` падал с `could not read Username for 'https://github.com'` при клонировании memory repo (`OPENCODE_MEMORY_REMOTE` = HTTPS GitHub URL). Git не подставляет `GITHUB_TOKEN` автоматически для HTTPS-remote — в non-interactive контексте (Docker container, нет tty) prompt блокирует clone, скрипт висит или падает.

Временный fix применялся вручную в контейнере:
```bash
git config --global url."https://x-access-token:$GITHUB_TOKEN@github.com/".insteadOf https://github.com/
```

Но `~/.gitconfig` живёт в overlay container filesystem (Docker) и **теряется при `docker compose restart`**. После рестарта memory-clone снова падал — manual fix не persistent.

Нужен детерминированный механизм, который гарантированно применяет insteadOf при каждом запуске `setup-memory.sh` (вызывается через memory-setup tool при старте opencode).

## Решение

Встроить guarded `git config --global url.insteadOf` блок в `.opencode/scripts/setup-memory.sh`, перед `git clone`:

```bash
if [ -n "${GITHUB_TOKEN:-}" ]; then
  git config --global url."https://x-access-token:${GITHUB_TOKEN}@github.com/".insteadOf https://github.com/
fi
```

- **Guarded check** — если `GITHUB_TOKEN` пуст/unset, блок пропускается без ошибки (локальная dev-среда с file-based mock remote не падает).
- **Inside clone-branch** — helper стоит внутри `if [ ! -d "$MEMORY_DIR/.git" ]`, срабатывает только при первом клонировании. На pull-path не нужен: `origin` URL уже сохранён в `.git/config` клона.
- **Idempotent** — `git config --global url.<prefix>.insteadOf` перезаписывает значение при повторном вызове, не дублирует entry.
- **4 теста** в `tests/test_setup_memory.py`: grep check (insteadOf presence + ordering before clone), grep check (GITHUB_TOKEN guarded), functional idempotency (2x run → 1 insteadOf entry in isolated HOME), functional skip (no token → no insteadOf).

### Альтернативы

- **Dockerfile ENTRYPOINT / `.bashrc` hack** (`RUN echo 'git config ...' >> /root/.bashrc`) — отклонено: `.bashrc` читается только interactive shell'ом, non-interactive container (opencode spawn) его не читает. ENTRYPOINT hack смешивает git-config с container lifecycle, менее детерминированно чем скрипт, вызываемый через tool.

- **Hard-fail если `GITHUB_TOKEN` unset** — отклонено: ломает локальную dev-среду (mock file-remote, offline tests). Guarded check (`if [ -n ... ]`) позволяет скрипту работать с любым remote — HTTPS GitHub (нужен token) или file-based mock (token не нужен).

- **Применять insteadOf на каждом запуске (вне clone-ветки)** — отклонено: на pull-path `origin` URL уже сохранён в `.git/config`, insteadOf не нужен. Дублирование вызова `git config --global` на каждом запуске — лишняя запись в gitconfig без пользы (хоть и idempotent). Clone-ветка — единственное место, где remote URL впервые передаётся git.

## Альтернативы
См. блок «Альтернативы» выше. Кратко: отклонены — Dockerfile/`.bashrc` hack (non-interactive), hard-fail on missing token (ломает dev), insteadOf на каждом запуске (лишнее). Выбран guarded insteadOf внутри clone-ветки (детерминированно, idempotent, dev-safe).