tea-guard: resolve and rewrite --login instead of env-checking

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>
This commit is contained in:
naudachu
2026-05-30 16:26:54 +05:00
parent d4aa0a9038
commit bac45028bf
3 changed files with 188 additions and 78 deletions
+29 -16
View File
@@ -1,6 +1,6 @@
---
name: use
description: Reference docs for the `tea` CLI — Gitea's command-line client. Load when the user asks about Gitea repos, issues, pulls, releases, actions, or other Gitea entities, to look up the right `tea` command and flags. Every tea call must carry --login "$GITEA_LOGIN" (enforced by the tea-guard hook; set it with /tea:login).
description: Reference docs for the `tea` CLI — Gitea's command-line client. Load when the user asks about Gitea repos, issues, pulls, releases, actions, or other Gitea entities, to look up the right `tea` command and flags. Always write the login as the literal placeholder --login "$GITEA_LOGIN" the tea-guard hook substitutes the operator-pinned login; set it with /tea:login.
---
# /tea:use — tea CLI reference
@@ -9,18 +9,27 @@ Reference material for the `tea` CLI (Gitea's official command-line client).
Use these docs to look up commands, flags, filters, and output fields before
running `tea` via Bash.
## Login is mandatory (enforced)
## Login: always write the placeholder, never a name (enforced)
Every `tea` invocation that touches Gitea MUST include `--login "$GITEA_LOGIN"`
(or `-l "$GITEA_LOGIN"`). This is enforced by the **`tea-guard`** PreToolUse
hook — a `tea` command without `--login` is blocked before it runs. If
`$GITEA_LOGIN` is unset, run **`/tea:login`** to pin one.
Every `tea` invocation that touches Gitea MUST carry the login as the **literal
placeholder** `--login "$GITEA_LOGIN"` (or `-l "$GITEA_LOGIN"`). Do **not**
substitute an actual login name yourself.
Why: without `--login`, `tea` silently falls back to the machine's default
login (possibly the user's personal account) and writes under the wrong
identity. The login value is pinned per-project in `.claude/settings.local.json`
under `env.GITEA_LOGIN`. Only `tea logins list` and `tea --version/--help` are
exempt from the guard.
The **`tea-guard`** PreToolUse hook enforces this and resolves it:
- no `--login` → blocked.
- `--login "$GITEA_LOGIN"` → the hook reads the operator's pinned login from
`.claude/settings.local.json` (`env.GITEA_LOGIN`) **at call time** and
rewrites the command to use that literal before it runs.
- `--login <some-name>` or any other variable → blocked. You may not choose the
login; only the operator does (via `/tea:login`).
- no login pinned → blocked with a pointer to run `/tea:login`.
Why: without an explicit login `tea` silently falls back to the machine's
default (possibly the user's personal account), and a login *you* pick may be
the wrong identity. Pinning is the operator's decision; the hook guarantees it.
The pin takes effect immediately — no restart. Only `tea logins list` and
`tea --version/--help` are exempt from the guard.
## How to use
@@ -28,12 +37,14 @@ exempt from the guard.
releases, times, repos, branches, actions, webhooks, comments,
notifications, etc.
2. Find the matching command in the index below.
3. Run it via Bash with the login, e.g.
3. Run it via Bash with the placeholder login, e.g.
`tea issues list --login "$GITEA_LOGIN" --repo owner/repo --state open`.
(The hook rewrites `"$GITEA_LOGIN"` to the operator-pinned login.)
`tea` auto-detects owner/repo from `$PWD` inside a git repo; otherwise pass
`--repo owner/repo` (or `-r`). Login is **not** auto-detected — it is pinned
per-project (see `/tea:login`). Config lives in `$XDG_CONFIG_HOME/tea`.
per-project by the operator (see `/tea:login`) and injected by the guard.
Config lives in `$XDG_CONFIG_HOME/tea`.
## Index
@@ -91,12 +102,14 @@ request payload to `$PWD/tmp/` first, then POST via `tea api`.
| Create release | `POST repos/{owner}/{repo}/releases` |
Short single-line bodies (e.g. `tea comment 42 "lgtm" --login "$GITEA_LOGIN"`)
are still fine via entity commands.
are still fine via entity commands. Always the placeholder, never a login name.
## Tips
- Pass `-o json` for structured output when parsing programmatically.
- Use `--fields, -f` to narrow columns.
- Pagination: `--page, -p <n>` and `--limit, --lm <n>` (defaults 1 / 30).
- If a `tea` command is blocked by `tea-guard`, you forgot `--login` or
`$GITEA_LOGIN` is unset — add the flag or run `/tea:login`.
- If a `tea` command is blocked by `tea-guard`: either you forgot
`--login "$GITEA_LOGIN"`, you wrote a literal login name instead of the
placeholder (not allowed — let the guard substitute), or no login is pinned
(run `/tea:login`).