* 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>
7.2 KiB
pr: 175 title: fix(repo-readme): create mode does not overwrite existing local README
Что сделано
Фикс бага #148 в тулзе create-readme (.opencode/tools/create-readme.ts):
локальный режим (file_path, без repo) вызывал writeFileSync(file_path, ...)
и readFileSync(file_path, ...) с относительным file_path (default
README.md), который резолвился относительно CWD процесса плагина Bun, а НЕ
относительно context.worktree (рабочей директории сессии пользователя).
Результат: отчёт README.md created at README.md — ложный success, файл на
диске не менялся.
Root cause: spawnSync вызовы в удалённом режиме корректно передавали
cwd: context.worktree, но fs.*Sync в локальном режиме — нет, пути
резолвились не там.
Изменения:
-
.opencode/tools/create-readme.ts:- Добавлен
import path from "path". absPath = path.resolve(context.worktree, file_path)— путь резолвится относительно рабочей директории сессии.writeFileSync(absPath, ...)иreadFileSync(absPath, ...)— запись/чтение в/из корректной директории. Существующий README гарантированно перезаписывается (создаётся новый если не существует).- Удалённый режим (
args.repo) не тронут — уже использовалcwd: context.worktreeдляspawnSync.
- Добавлен
-
tests/_ts_loader.mjs— расширение лоадера для тестированияcreate-readme.ts(локальный режим используетfs):stripTs: обработкаimport { readFileSync, writeFileSync } from "fs"→const { ... } = require("fs").stripTs:g-флаг для стрипаtype X = ...(несколько алиасов в одном файле:Feature,CustomSection,CreateArgs).stripTs: стрип многострочныхtype X = { ... }object-типов.stripTs: обобщение стрипа return type (объектный литерал как return typevalidateReadme(...): { ok: boolean; issues: string[] }).stripTs: стрип type annotations вconst/let/var x: Type = ....stripTs: стрип TS non-null assertionsx!→x(не трогает!=,!==, унарный!foo).loadTool(spawnSyncImpl, fsImpl):fsпередаётся в sandbox черезnew Function(..., "fs", ...)иrequire("fs")shim возвращает модуль (настоящийnode:fsпо умолчанию или mock).
-
tests/test_create_readme_tool.py— новый файл, 14 регрессионных тестов:test_loader_can_load_tool— sanity (args declared).test_local_create_overwrites_existing_readme— регрессия #148: существующий README перезаписывается (mtime обновляется, delimiter-теги присутствуют, старый контент отсутствует).test_local_create_creates_new_readme— создаёт новый файл.test_local_create_custom_subdir_file_path— пишет в поддиректорию.test_remote_create_makes_two_spawnsync_calls— удалённый режим: 2 вызова (GET sha + PUT), не сломан фиксом.test_remote_create_passes_worktree_cwd—cwd=context.worktreeв opts.test_local_validate_reads_file_path— локальный validate читает изfile_path.test_local_validate_reports_missing_delimiters— malformed README → issues.- 6 валидационных ошибок: missing repo_name, missing tagline_ru, uppercase repo_name, latin tagline_ru, cyrillic tagline_en, empty features_en.
-
.opencode/skills/repo-readme/SKILL.md— раздел 3: уточнение, чтоfile_pathрезолвится относительноcontext.worktreeи существующий файл перезаписывается. -
docs/project-map/README.md— обновлены описанияcreate-readme.ts,_ts_loader.mjs, добавленtest_create_readme_tool.py.
Почему
Issue #148: create-readme (mode create, локальный режим, без repo)
возвращал README.md created at README.md, но файл на диске не изменялся —
stat показывал прежний mtime, delimiter-теги отсутствовали. Скилл
repo-readme (раздел 6) обещает «перезапишет README.md (локально) через
fs.writeFileSync» — фактически ложный success. Тот же root cause затрагивал
validate (читал из неверного пути, не находил файл → ошибка вместо
валидации реального README).
Фикс path.resolve(context.worktree, file_path) гарантирует, что путь
резолвится относительно рабочей директории сессии (как и spawnSync в
удалённом режиме), а не относительно CWD процесса плагина. Перешёл от
«relative path против CWD процесса» к «absolute path относительно worktree» —
симметрично с тем, как spawnSync получает cwd.
Pending
—
Watch out
Лоадер tests/_ts_loader.mjs расширен для поддержки fs и расширенного
TS-стриппинга (многострочные type-алиасы, non-null assertions, type
annotations в переменных). Эти расширения безопасны для существующих тулз
(проверено: commit.ts, draw-image.ts, create-pr.ts,
create-issue.ts — все загружаются и 459 тестов проходят). Но если будущая
тулза использует более сложный TS-синтаксис (generics в вызовах, conditional
types, template literal types), лоадер может потребовать дальнейшего
расширения stripTs.
Тесты локального режима используют абсолютный file_path во временной
директории (tempfile.TemporaryDirectory), чтобы избежать перезаписи
README репозитория (лоадер хардкодит worktree: REPO_ROOT, относительный
путь README.md резолвился бы в REPO_ROOT/README.md). Для полноценного
теста path.resolve(context.worktree, relative) потребовалось бы параметризовать
worktree в лоадере — оставлено как future improvement (зафиксировано в
комментарии теста).