091dceec1d
An issue was a Gitea row that happened to be cached locally: its identity was the tracker's number (42.md), its dependencies were tracker numbers (depends: [#12]), and a local issue existed only as a draft that push deleted on success. Nothing could be planned or tracked without a tracker. Split into layers, with knowledge flowing one way: skills/issue DOMAIN what an issue is: format, validation, dep graph ^ offline; stdlib imports only, no subprocess | imports skills/sync BRIDGE map.py md <-> Gitea JSON, pure, no I/O _gitea.py login pin, api, pagination, filters skills/use REFERENCE tea CLI docs for non-issue entities skills/issue never imports skills/sync. Delete the sync layer and the domain keeps working. Identity is now a slug derived from the title (wire-sqlc-appclick.md) and is stable across retitles and pushes. Tracker numbers live in a `gitea:` field, never in a file name and never in `depends:`; the pair is indexed in .remote.json, which is a cache over the files, not a second source of truth. Behavior changes: - Pushing is additive. The file is never deleted; it gains gitea:/url:/ synced: and origin: flips from local to gitea. `origin: local` is a durable state, not a pending one. - Pushes go in topological order so dependencies get numbers first. - The dependency graph is computed offline from `depends:` metadata; body prose is passed through unchanged in both directions rather than being rewritten between slugs and #N. - `origin` is domain-owned (whether work exists elsewhere is a fact about the work); the handle and how to reach it stay with sync. Script moves: issue_get.py -> sync/pull.py issue_push.py -> sync/push.py issue_list.py -> sync/remote.py issue_index.py -> issue/issue_index.py _tea.py -> split into issue/issue.py, sync/map.py, sync/_gitea.py New: issue/issue_new.py, issue/issue_check.py, issue/issue_tree.py, and sync/comment.py — comment posting was the last issue operation still hand-rolled through raw `tea api`. references/issue-format.md moves to skills/issue/references/format.md; label hex colors move out of it into map.py, since a color is how a tracker paints a chip, not what an issue is. Verified: offline path end to end (new, check, tree, index, push --dry-run) and read-only against Gitea (remote listing, pull with mapping, comment guard). Write paths of push.py and comment.py are not exercised here. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
135 lines
6.4 KiB
Markdown
135 lines
6.4 KiB
Markdown
---
|
|
name: use
|
|
description: Reference docs for the `tea` CLI — Gitea's command-line client. Load when the user asks about Gitea repos, pulls, releases, milestones, labels, actions, webhooks, 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:auth. Issues are NOT handled here: use /tea:issue to work on them and /tea:sync to move them to and from Gitea.
|
|
---
|
|
|
|
# /tea:use — tea CLI reference
|
|
|
|
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.
|
|
|
|
## Issues are somewhere else
|
|
|
|
Do **not** reach for `tea issues` or `tea api .../issues/...` to read or create
|
|
an issue. Two skills own that, and they keep the payload out of your context:
|
|
|
|
| Skill | Scope |
|
|
|---|---|
|
|
| `/tea:issue` | issues as units of work — create, read, grep, validate, dependency graph. Offline. |
|
|
| `/tea:sync` | moving issues between the local store and Gitea — pull, push, comment. |
|
|
|
|
This skill covers everything else Gitea has: pulls, releases, milestones,
|
|
labels, repos, branches, actions, webhooks, notifications, times.
|
|
|
|
## Login: always write the placeholder, never a name (enforced)
|
|
|
|
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.
|
|
|
|
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:auth`).
|
|
- no login pinned → blocked with a pointer to run `/tea:auth`.
|
|
|
|
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
|
|
|
|
1. Identify the entity in the request: pulls, labels, milestones, releases,
|
|
times, repos, branches, actions, webhooks, notifications, etc.
|
|
2. Find the matching command in the index below.
|
|
3. Run it via Bash with the placeholder login, e.g.
|
|
`tea pulls 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 by the operator (see `/tea:auth`) and injected by the guard.
|
|
Config lives in `$XDG_CONFIG_HOME/tea`.
|
|
|
|
## Index
|
|
|
|
- [tea CLI overview](references/tea/index.md) — global flags, common options, output formats
|
|
- [ENTITIES](references/tea/entities.md) — issues, pulls, labels, milestones, releases, times, repos, branches, actions, webhooks, comment
|
|
- [HELPERS](references/tea/helpers.md) — open, notifications, clone, api
|
|
- [MISC](references/tea/misc.md) — whoami, admin
|
|
- [SETUP](references/tea/setup.md) — logins, logout, ssh-keys
|
|
|
|
The canonical issue format moved to
|
|
[`../issue/references/format.md`](../issue/references/format.md) — it describes
|
|
local files, not `tea` commands.
|
|
|
|
## Rich payloads — write to `$PWD/tmp/` first, then `tea api`
|
|
|
|
Entity subcommands (`tea comment`, `tea pulls create`, `tea releases create`, …)
|
|
are built for humans at a TTY. With a large or formatted body they can hang
|
|
silently — an empty-looking positional arg triggers `$EDITOR` fallback, or a
|
|
scope/confirm prompt waits on a TTY that doesn't exist. The harness eventually
|
|
kills the process (e.g. exit 144 = 128 + SIGURG on macOS).
|
|
|
|
**Rule:** for any non-trivial body (multi-line, or containing markdown / code
|
|
fences / backticks / pipes / tables), bypass entity commands. Save the full
|
|
request payload to `$PWD/tmp/` first, then POST via `tea api`.
|
|
|
|
Issues and issue comments are already wrapped — use `/tea:sync` rather than
|
|
hand-rolling their JSON. The procedure below covers everything else.
|
|
|
|
### Procedure
|
|
|
|
1. Ensure the target dir exists: `mkdir -p tmp/{kind}` where `{kind}` is
|
|
`pull`, `release`, etc.
|
|
2. Write the **complete request body as JSON** to `$PWD/tmp/{kind}/<slug>.json`.
|
|
One file = one request. Use a quoted heredoc to avoid shell expansion:
|
|
```bash
|
|
mkdir -p tmp/release
|
|
cat > tmp/release/v0-2-0.json <<'EOF'
|
|
{"tag_name": "v0.2.0", "name": "v0.2.0", "body": "## Changes\n\nMulti-line markdown with `code`."}
|
|
EOF
|
|
```
|
|
Newlines inside the body must be encoded as `\n` in the JSON string. If
|
|
composing programmatically, pipe through
|
|
`jq -Rs '{body: .}' < body.md > tmp/release/v0-2-0.json`.
|
|
3. POST with `tea api`, passing the file with `-d @<path>`:
|
|
```bash
|
|
tea api --login "$GITEA_LOGIN" \
|
|
-X POST -d @tmp/release/v0-2-0.json \
|
|
repos/{owner}/{repo}/releases
|
|
```
|
|
4. Keep the file. `tmp/` should be gitignored; the saved payload is useful for
|
|
retries, edits (`PATCH`), and debugging failed posts.
|
|
|
|
### Common endpoints
|
|
|
|
| Action | Method + endpoint |
|
|
|---|---|
|
|
| Create PR | `POST repos/{owner}/{repo}/pulls` |
|
|
| Edit PR body or title | `PATCH repos/{owner}/{repo}/issues/{n}` |
|
|
| Comment on a PR | `POST repos/{owner}/{repo}/issues/{n}/comments` |
|
|
| Edit comment | `PATCH repos/{owner}/{repo}/issues/comments/{id}` |
|
|
| Create release | `POST repos/{owner}/{repo}/releases` |
|
|
| Create milestone | `POST repos/{owner}/{repo}/milestones` |
|
|
|
|
Short single-line bodies (e.g. `tea comment 42 "lgtm" --login "$GITEA_LOGIN"`)
|
|
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`: 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:auth`).
|