bac45028bf
The previous guard required $GITEA_LOGIN to be set in the Bash environment,
which (a) only happens after a session restart and (b) let Claude name any
login it liked as long as one was set. Two failures: pinning needed a restart
to take effect, and Claude could pick the wrong identity from memory.
Rewrite the guard (now python3 for JSON in/out) to RESOLVE the login itself:
- Claude must write the literal placeholder --login "$GITEA_LOGIN".
- The hook reads the operator's pin from .claude/settings.local.json
(env.GITEA_LOGIN) at call time — from the FILE via CLAUDE_PROJECT_DIR/cwd
walk-up — and rewrites the command to that literal via updatedInput.
- A literal login, another variable, an empty value, or a missing --login are
all blocked: Claude may not choose the identity, only the operator may.
- No pin -> block with a pointer to /tea:login.
Effect: pinning works in the same session (no restart), and Claude can no
longer act under a login it picked. /tea:login now mandates an explicit
operator choice (AskUserQuestion), never inferring from memory. /tea:use
documents the placeholder-only contract.
Guard unit-tested across 13 rewrite/block/passthrough cases incl. -l,
--login=, ${...}, compound+walkup+pipe. claude plugin validate passes.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2.5 KiB
2.5 KiB
name, description
| name | description |
|---|---|
| login | Pin the Gitea login used by the tea CLI in this project. Run when the tea-guard hook reports no login is pinned, or when the user types /tea:login. Enumerates available logins, makes the OPERATOR pick one, and persists it to .claude/settings.local.json. The pin takes effect immediately — no restart. |
/tea:login — pin the project Gitea login
Goal: have the operator select exactly one tea login for this project and
persist it to .claude/settings.local.json under env.GITEA_LOGIN. The
tea-guard hook reads this file at call time and rewrites every
--login "$GITEA_LOGIN" to the pinned value, so the choice takes effect
immediately, with no session restart.
The one hard rule: the operator chooses, never you
Picking the wrong identity is the exact failure this command exists to prevent. So:
- ALWAYS present the choice with
AskUserQuestionand let the operator pick — even if memory, context, the repo URL, or a previous session suggests a "likely" login. Do not auto-select from memory or infer it. A wrong guess writes under the wrong account. - The only exception: exactly one login exists on the machine — then propose it and still confirm before writing.
Steps
- Enumerate logins (allowed by the guard even with no pin):
tea logins list -o json - No logins: stop and ask the operator to run
tea logins addthemselves — it is interactive (prompts for URL/token). Do not run it for them. - One login: propose it; confirm before writing.
- Several logins:
AskUserQuestionwith each login'sname,user, andurlso the operator's choice is unambiguous. Never decide for them. - Merge the chosen name into
.claude/settings.local.jsonunderenv(do not clobber other keys):{ "env": { "GITEA_LOGIN": "<chosen-name>" } } - Done — it is live. The guard resolves the pin from the file on the next
teacall; no restart needed. Tell the operator which login is now pinned.
Identity-safety rules
- NEVER run commands that mutate logins or global login state:
tea logins add/edit/delete/default,tea logout. Read-onlytea logins listis the only allowed login command. - If a
teacall fails with a permission/scope error, report it. Do NOT try to fix it by switching to, or editing, a different login. - If you ever see
no gitea login detected, falling back to login '...', treat it as a hard failure: stop, do not act on the result, surface it.