* fix(create-readme): resolve file_path against context.worktree * test(loader): support fs imports and extended TS stripping * test(create-readme): add regression tests for local overwrite * docs(repo-readme): note file_path resolves against worktree * docs(handoff): set PR number --------- Co-authored-by: opencode-agent <agent@opencode.local>
52 lines
No EOL
3.6 KiB
Markdown
52 lines
No EOL
3.6 KiB
Markdown
# ADR-073: create-readme local-mode path resolution via context.worktree
|
||
|
||
## Статус
|
||
Accepted (2026-07-31)
|
||
|
||
## Контекст
|
||
|
||
Тулза `create-readme` (`.opencode/tools/create-readme.ts`) работает в двух
|
||
режимах: локальном (`file_path`, без `repo`) и удалённом (`repo: owner/name`
|
||
через `gh api`). В удалённом режиме `spawnSync` вызовы корректно передавали
|
||
`cwd: context.worktree` — рабочую директорию сессии пользователя. В локальном
|
||
режиме `writeFileSync(file_path, ...)` / `readFileSync(file_path, ...)`
|
||
вызывались с относительным `file_path` (default `README.md`), который
|
||
резолвился относительно **CWD процесса плагина Bun**, а не относительно
|
||
`context.worktree`. В продакшене CWD плагина ≠ рабочая директория
|
||
пользователя — файл писался/читался не туда, отчёт `README.md created at
|
||
README.md` был ложным success (issue #148).
|
||
|
||
Асимметрия: `spawnSync` получал `cwd`, а `fs.*Sync` — нет. Тестовый лоадер
|
||
`tests/_ts_loader.mjs` не поддерживал `import { readFileSync, writeFileSync }
|
||
from "fs"` и расширенный TS-синтаксис (многострочные type-алиасы, non-null
|
||
assertions, type annotations в переменных) — локальный режим тулзы нельзя
|
||
было протестировать.
|
||
|
||
## Решение
|
||
|
||
1. **Резолв пути относительно worktree**: `const absPath =
|
||
path.resolve(context.worktree, file_path)` — симметрично с `spawnSync`
|
||
в удалённом режиме. `writeFileSync(absPath, ...)` / `readFileSync(absPath,
|
||
...)` работают с абсолютным путём. Существующий файл гарантированно
|
||
перезаписывается.
|
||
|
||
2. **Расширение `_ts_loader.mjs`**: `stripTs` теперь обрабатывает `fs`
|
||
импорты, многострочные `type X = { ... }`, type annotations в
|
||
`const/let/var`, non-null assertions `x!`. `loadTool(spawnSyncImpl,
|
||
fsImpl)` передаёт `fs` модуль в sandbox. Это открывает возможность
|
||
тестировать любую тулзу, использующую `fs` в локальном режиме.
|
||
|
||
## Альтернативы
|
||
|
||
- **`process.chdir(context.worktree)` в начале `execute()`**: меняло бы CWD
|
||
процесса, но побочные эффекты на другие тулзы в том же процессе
|
||
неприемлемы (гонки, неявное состояние). Отвергнуто.
|
||
|
||
- **Передача `file_path` как абсолютного всегда (валидировать на входе)**:
|
||
ломало бы существующие вызовы с относительным `file_path` (default
|
||
`README.md`). `path.resolve(worktree, file_path)` прозрачно обрабатывает
|
||
оба случая (относительный → относительно worktree; абсолютный → как есть).
|
||
|
||
- **Не расширять лоадер, тестировать только через интеграцию**: медленнее,
|
||
хрупче, не ловит регрессии на уровне `execute()`. Расширение лоадера
|
||
позволяет точечные unit-тесты с реальным `fs` во временных директориях. |