fix(tools): add spawnSync timeout to local git calls #47
Loading…
Reference in a new issue
No description provided.
Delete branch "fix/tools/synctimeout-git-calls"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Что сделано
Добавил
timeoutопцию кspawnSync("git", ...)во всех TS-тулах, где её не было (кромеresolveForgejoRepoв_shared.ts— уже пофикшено в PR#41). При timeout возвращается читаемая ошибка вместо пустого stdout.merge-pr.ts—git()helper (строки 5-18): добавленtimeout: 10000(10с). Покрывает все 6 call sites (branch --list, rev-parse, checkout, pull, branch -D ×2). При timeout возвращает{ status: null, stderr: "[git] <cmd> timed out after 10000ms" }— merge-pr graceful-fail с сообщением.create-pr.ts(строка 62) —spawnSync("git rev-parse --abbrev-ref HEAD"): добавленtimeout: 5000(5с, быстрая операция). При timeout возвращает❌ [git] <cmd> timed out after 5000ms.commit.ts— 3spawnSyncвызова:git log --oneline -5(recentCommits):timeout: 10000git diff --cached --name-only:timeout: 10000git commit -m:timeout: 30000(30с — pre-commit hooks: ruff, mypy могут быть медленными на больших репо)gitTimeoutErr(cmd, ms)→[git] <cmd> timed out after Nms. Для commit добавлен hint про.git/index.lock.Почему
PR#41 (issue #40) добавил timeout только к
resolveForgejoRepoв_shared.ts. ОстальныеspawnSync("git", ...)в TS-тулах hang'али при медленном git (git pullна медленном remote,git checkoutна FUSE/NFS,git commitс большим diff или медленными pre-commit hooks). Агент не получал ошибки — просто зависал. Теперь fail-fast с читаемой ошибкой, агент может retry.Контракт:
spawnSync(cmd, args, { timeout: N })— Node/Bun поддерживает. При timeout процесс убивается SIGTERM →result.signal === "SIGTERM",result.status === null.Watch out
git pullвmerge-pr.ts:78— 10с может быть tight на очень медленном remote (Forgejo за Nginx, медленный response). Если tight — retry на уровне выше (merge-pr уже возвращает читаемую ошибку, агент повторяет).git commitс pre-commit hooks на очень большом репо может занять >30с — тогда commit fail с сообщением про.git/index.lock. Агент удаляет lock и retry..git/index.lock— упомянуто в ошибке дляcommit.ts. Дляmerge-pr.ts/create-pr.tslock менее вероятен (только read-операции), hint не добавлен.timeoutoption + проверкаsignal === "SIGTERM". Существующие вызовы с быстрым git работают как раньше.cover-*.svgв.opencode/draw-image/templates/,node_modules/) вне scope — не коммитил.Pending
merge-pr.ts/create-pr.ts/commit.tsнет (только_shared.test.tsдля_shared.ts). Тесты для spawnSync timeout требуют mock'аchild_process.spawnSync— вне scope этого fix.subprocess.rungit calls (pipeline-status.py,spec-status.py,project-status.py) — issue Волны 1 (Python oracles), вне scope (см. "Вне scope" в issue #44).curlв skills — issue Волны 2, вне scope.Closes #44
Code Review Summary
PR добавляет
spawnSynctimeout к локальным git-вызовам в 3 TS-тулах (merge-pr.ts,create-pr.ts,commit.ts) — волна 3 в рамках hardening против зависаний git. Изменения минимальны, backward-compatible, не ломают существующие контракты.Что правильно
git()helper централизованно добавляетtimeout: 10000ко всем 6 call sites через одну точку. При timeout (signal === "SIGTERM" && status === null) возвращает объект сstatus: nullи читаемымstderr— callers'ы уже проверяютstatus === 0/status !== 0, так чтоnullкорректно попадает в error path. КонстантаGIT_TIMEOUT_MSвынесена, не magic number.GIT_LOG_TIMEOUT_MS,GIT_DIFF_TIMEOUT_MS,GIT_COMMIT_TIMEOUT_MS).git commitимеет больший timeout (30000ms) для pre-commit hooks — корректное разделение.gitTimeoutErr()helper устраняет дублирование форматата ошибки..git/index.lockпри SIGTERM отgit commit— практически полезно, т.к. git при kill может оставить lock и следующий commit упадёт.git rev-parse(быстрая операция, меньший timeout оправдан) + читаемая ошибка с полным cmd.timeoutoption, существующие вызовы и return-shapes сохранены. Cross-file impact: tools вызываются opencode runtime, oracle-скрипты не парсят их вывод — paired updates не требуются.Замечания (info, не блокирующие)
5000inline, в отличие отcommit.tsиmerge-pr.tsгде timeout'ы вынесены в константы. Для консистентности можно вынести вconst GIT_REV_PARSE_TIMEOUT_MS = 5000и использовать в сообщении об ошибке (сейчас5000msзахардкожено дважды: в option и в строке ошибки).recentCommits()при timeout возвращает[git] git log --oneline -5 timed out after 10000ms, которая потом вставляется вRecent commits:\n${recentCommits(...)}. Пользователь увидит "Recent commits:\n[git] git log --oneline -5 timed out after 10000ms" — semantically странно (это не список коммитов). Можно вернуть"(git log timed out)"чтобы визуально отличалось от реальных коммитов. Не блокирующее — edge case (git log зависает крайне редко).git()helper в merge-pr и spawnSync-call'ов в commit. В_shared.test.ts:232есть прецедент теста timeout дляresolveForgejoRepo— можно аналогично покрыть, но spawnSync-timeout сложно мокать без реального hang, поэтому info-level.Verdict: APPROVE