Resolve the login pin from the scripts' own location, not CWD #24
Reference in New Issue
Block a user
Delete Branch "%!s()"
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?
Summary
Весь слой
skills/syncне работает из git worktree: пин логина ищетсяхождением вверх от CWD, а worktree лежит вне основного чекаута, где нет
.claude/settings.local.json. Каждый скрипт падает с «no login pinned» ипредлагает
/tea:auth, хотя логин для проекта запинен иteaв том жекаталоге отрабатывает нормально.
Spec
none
Steps to reproduce
teaнапрямую:Expected
Шаг 2 отрабатывает. Логин запинен для проекта, скрипт лежит внутри репозитория
проекта, и
store_root()из соседнего слоя этот репозиторий находит — значитнайти его умеет и транспорт.
Actual
Шаг 2:
Шаг 4 при этом успешно отдаёт JSON: хук
tea-guardподставляет пин, потому чточитает его от каталога проекта, а не от CWD. То есть в одном и том же каталоге
teaлогин видит, а скрипты — нет, и сообщение зовёт запинить то, что ужезапинено.
--dry-runпроходит целиком — сети он не касается, — так что отказ всплываетровно в тот момент, когда работа готова к отправке.
Три следствия, и каждое хуже предыдущего:
Совет в тексте ошибки ведёт не туда.
/tea:authвнутри worktree создаствторой
settings.local.jsonв каталоге, который будет удалён вместе сworktree, — и попросит оператора выбирать логин, который уже выбран.
Обходной путь неочевиден и нигде не записан: запускать скрипты worktree с
CWD внутри основного чекаута.
Обходной путь портит данные. Стор резолвится от
__file__, то есть внутрьworktree, но не всегда: часть скриптов требует явного
--out <worktree>/tmp/issues, иначе запись уходит в чужой стор — а стороператора трогать нельзя. И главное:
push.py:202-214(git_branch) читаетветку по CWD, то есть ветку основного чекаута, и в Gitea уезжает
ref: mainвместо ветки, на которой работа реально живёт. Ровно то поле, ради которого
branch:существует.Environment
Асимметрия внутри одного репозитория, и правильная половина уже написана:
skills/issue/scripts/issue.py:97—store_root()идёт вверх от__file__(
issue.py:78) до ближайшего.gitилиAGENTS.md. Работает из любогокаталога, worktree в том числе;
issue.repo_root(issue.py:81-95)специально умеет читать
.gitкак файл.skills/sync/scripts/_gitea.py:51—find_pin(start_dir=None)идёт вверх отstart_dir or ".".skills/sync/scripts/_gitea.py:72—require_login()зовётfind_pin(os.getcwd()), и другого источника у него нет.Порядок поиска у хука и у скриптов разный, и записан он в двух местах:
hooks/tea-guard.sh:120CLAUDE_PROJECT_DIR, затемcwdиз payload, затемos.getcwd()skills/sync/scripts/_gitea.py:72os.getcwd()В worktree обе попытки пусты — ни от CWD, ни от каталога скрипта
.claude/settings.local.jsonне находится, потому что он лежит в основномчекауте и не отслеживается git:
Что worktree — это дерево того же репозитория, git знает:
.gitв нём файл,а
git rev-parse --git-common-dirуказывает на общий каталог, рядом с которыми лежит настоящий корень проекта. Ни того ни другого транспорт сейчас не
спрашивает.
Задевает это ровно то, ради чего скрипты и написаны: работа над issue в
отдельной ветке. Хук
tea-guardот проблемы не страдает, так что несогласиедвух путей резолва видно только по ошибке скрипта. Затронуты все скрипты,
зовущие
_gitea.require_login:pull.py,push.py,comment.py,remote.py,labels.py,wiki_*.py.Воспроизведено тремя независимыми агентами на ветках
main,fix/limit-bounds-the-writeиfix/no-store-for-label-payloads.tea 0.14.1/0.14.2, Python 3.14.5, macOS 25.5.0.
Constraints
Резолв не переносится на
__file__. Плагин, установленный вне репозиторияи наведённый на чужой проект, не должен смотреть на свой собственный каталог —
поиск остаётся от CWD вверх, а worktree добавляется отдельной веткой поиска
через
gitdir:из файла.git.Acceptance criteria
skills/sync/scripts/находит пин, будучи запущенным изworktree с CWD внутри него
он через
gitdir:в файле.git, а не через__file__становится
месте
settings.local.jsonв worktree не создаётсяbranch:у issue, отправленной из worktree, равен ветке worktree, а неветке основного чекаута
skills/issue/scripts/иskills/page/scripts/по-прежнему stdlib-only и про логин не знают
оно не должно превращаться в «нашли не тот»
.claude/settings.local.json, worktreeрядом с ним, запуск оттуда находит логин; без файла — по-прежнему ошибка
push.pyиз worktree отправляетbranch:этого worktreefix/limit-bounds-the-writeto fix/limit-bounds-the-write