diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json index 3e59661..9cbe67f 100644 --- a/.claude-plugin/plugin.json +++ b/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "tea", - "description": "Gitea CLI (tea) reference plus a mandatory-login guard. Ships /tea:auth (pin a login) and /tea:use (command reference), and a PreToolUse hook that blocks any tea command that would touch Gitea without --login.", - "version": "1.0.0", + "description": "Gitea CLI (tea) reference plus a mandatory-login guard. Ships /tea:auth (pin a login), /tea:use (command reference), /tea:issue (create issues in a canonical format), and a PreToolUse hook that blocks any tea command that would touch Gitea without --login.", + "version": "1.1.0", "author": { "name": "naudachu" }, diff --git a/README.md b/README.md index 6756a7c..e59f1a6 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,7 @@ A Claude Code plugin that gives Claude a reference for the `tea` CLI and enforce |---|---| | `/tea:auth` skill | Prompts you to pick a Gitea login and pins it to the project | | `/tea:use` skill | Tea CLI reference — loads command docs on demand | +| `/tea:issue` skill | Creates issues in a canonical format (typed labels, fixed sections) | | `tea-guard` hook | PreToolUse hook that blocks or rewrites every `tea` invocation | ## Prerequisites @@ -39,7 +40,7 @@ This is a Claude Code plugin — install it through the plugin marketplace, not /plugin install tea@tea ``` -The skills (`/tea:auth`, `/tea:use`) and the `tea-guard` hook load immediately. Use `/plugin` to enable, disable, or update it later. +The skills (`/tea:auth`, `/tea:use`, `/tea:issue`) and the `tea-guard` hook load immediately. Use `/plugin` to enable, disable, or update it later. > The marketplace registration is written to `extraKnownMarketplaces` and the plugin to `enabledPlugins` in your settings automatically — you don't edit those by hand. There is **no** top-level `"plugins"` settings key; if you've added one from older instructions, remove it. @@ -79,4 +80,6 @@ skills/ auth/SKILL.md /tea:auth skill use/SKILL.md /tea:use skill use/references/tea/ tea CLI reference docs + use/references/issue-format.md canonical issue format (types, templates) + issue/SKILL.md /tea:issue skill ``` diff --git a/skills/issue/SKILL.md b/skills/issue/SKILL.md new file mode 100644 index 0000000..73259b7 --- /dev/null +++ b/skills/issue/SKILL.md @@ -0,0 +1,48 @@ +--- +name: issue +description: Create a Gitea issue in the project's canonical format. Run when the user asks to file/create an issue, or types /tea:issue. Ensures exclusive type/* labels exist, composes the body from the type's template, and posts via tea api. Format lives in the use skill's references. +--- + +# /tea:issue — create an issue in the canonical format + +Thin procedure on top of the canonical format defined in +[`../use/references/issue-format.md`](../use/references/issue-format.md). +Read that file first — it is the single source of truth for types, labels, +templates, and language rules. Login rules are the same as everywhere: +always `--login "$GITEA_LOGIN"`, never a literal name (see `/tea:use`). + +## Steps + +1. **Read the format**: load `../use/references/issue-format.md`. +2. **Pick the type** — `bug`, `feature`, `refactor`, or `draft` (for ideas + not ready for work). If it is not obvious from the request, ask the user + (one question). +3. **Ensure labels exist**: `tea labels list --login "$GITEA_LOGIN" -o json`. + For each missing `type/*` label, create it via `tea api` with + `"exclusive": true` exactly as shown in the format doc. Do NOT use + `tea labels create` for these — it cannot set exclusivity. +4. **Compose title and body** per the format: English imperative title without + a type prefix; the type's template with all sections present, in order, + headers in English, prose in Russian; `## Spec` filled with a repo path, + a URL, or the literal `none` — ask the user if you cannot determine which. +5. **Post via tmp/ + tea api** (the body is always multi-line, so entity + commands are off the table — see "Rich payloads" in `/tea:use`): + ```bash + mkdir -p tmp/issue + # write {"title": "...", "body": "...", "labels": []} as JSON + tea api --login "$GITEA_LOGIN" -X POST -d @tmp/issue/.json \ + repos/{owner}/{repo}/issues + ``` + The create endpoint takes label **IDs** (integers), not names — take them + from the `tea labels list` output of step 3 (or from the create response). + If labels fail to attach on create, fall back to + `PUT repos/{owner}/{repo}/issues/{n}/labels` with `{"labels": []}`. +6. **Report**: show the issue URL and the applied `type/*` label. + +## Editing an existing issue + +When asked to bring an existing issue to the format: fetch it +(`tea issues --login "$GITEA_LOGIN" -o json`), restructure the body into +the type's template without losing information, then +`PATCH repos/{owner}/{repo}/issues/{n}` with the new title/body and ensure +exactly one `type/*` label is set. diff --git a/skills/use/SKILL.md b/skills/use/SKILL.md index d3883f9..f809ac2 100644 --- a/skills/use/SKILL.md +++ b/skills/use/SKILL.md @@ -53,6 +53,10 @@ Config lives in `$XDG_CONFIG_HOME/tea`. - [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 +- [ISSUE FORMAT](references/issue-format.md) — canonical issue format: types + (`type/bug|feature|refactor` exclusive labels), templates, title and + language rules. MANDATORY whenever creating or editing an issue; the + `/tea:issue` skill is the guided procedure for it. ## Rich payloads — write to `$PWD/tmp/` first, then `tea api` diff --git a/skills/use/references/issue-format.md b/skills/use/references/issue-format.md new file mode 100644 index 0000000..d99966b --- /dev/null +++ b/skills/use/references/issue-format.md @@ -0,0 +1,139 @@ +# Issue format + +Canonical format for every issue created or edited via `tea`. Designed to be +unambiguous for both humans and LLMs: fixed English section headers in a fixed +order, verifiable acceptance criteria, one issue = one deliverable. + +## Language rules + +- **Issue title**: English, imperative mood, no type prefix — the type lives in + the label, not the title. Good: `Fix tea-guard crash on empty settings file`. + Bad: `fix: crash`, `[bug] crash`, `Крашится гвард`. +- **Section headers**: the exact English literals below, as `##` headings, in + the given order. Do not translate, rename, or reorder them. +- **Body prose** (text inside sections): Russian. + +## Types and labels + +Every issue carries exactly one `type/*` label: + +| Label | Meaning | +|---|---| +| `type/bug` | Something behaves incorrectly | +| `type/feature` | New capability or change in behavior | +| `type/refactor` | Internal restructuring; behavior must not change | +| `type/draft` | Idea captured for later; not ready for work | + +`type` is an **exclusive scope**: Gitea enforces at most one `type/*` label per +issue, but only if the labels were created with `exclusive: true`. The `tea +labels create` command (as of tea 0.14.2) cannot set that field, so missing +`type/*` labels MUST be created via `tea api`: + +```bash +tea api --login "$GITEA_LOGIN" -X POST \ + -d '{"name":"type/bug","color":"#ee0701","exclusive":true,"description":"Something behaves incorrectly"}' \ + repos/{owner}/{repo}/labels +``` + +Suggested colors: `type/bug` `#ee0701`, `type/feature` `#0e8a16`, +`type/refactor` `#1d76db`, `type/draft` `#cccccc`. + +## Shared rules + +- `## Summary` is always the first section; `## Acceptance criteria` is always + present (exception: `type/draft`). These two are the anchors every reader + (human or LLM) relies on. +- `## Spec` is **mandatory in every type**. Its value is a repo path + (`docs/specs/auth.md`), a URL, or the literal `none` when no spec exists. + Never omit the section and never invent a link — `none` is an explicit, + valid answer. +- Acceptance criteria are `- [ ]` checkboxes; each item is an objectively + checkable condition, not an aspiration. +- Code references use the `path/file.ext:line` form; related issues as `#N`. +- Screenshots are allowed but their content must be duplicated as text — an + LLM posting through `tea api` cannot read images. +- If acceptance criteria grow past ~5 unrelated items, split the issue. + +## Template: `type/bug` + +```markdown +## Summary +Что сломано и где проявляется, одно-два предложения. + +## Spec +`docs/specs/auth.md`, URL — или `none`. + +## Steps to reproduce +1. … +2. … + +## Expected +Что должно было произойти. + +## Actual +Что происходит на самом деле: вывод команды, лог. + +## Environment +Только релевантное: версии, ОС, конфигурация. + +## Acceptance criteria +- [ ] баг не воспроизводится по шагам выше +- [ ] добавлена проверка на регрессию (если применимо) +``` + +## Template: `type/feature` + +```markdown +## Summary +Что нужно сделать, одно-два предложения. + +## Spec +Ссылка или `none`. + +## Motivation +Какую проблему пользователя/системы это решает. + +## Acceptance criteria +- [ ] проверяемое условие +- [ ] … + +## Constraints +Что НЕ входит в объём; технические рамки. (опционально) +``` + +## Template: `type/refactor` + +```markdown +## Summary +Что перестраиваем и в каких файлах (`path/file:line`). + +## Spec +Ссылка или `none`. + +## Motivation +Чем плохо текущее состояние: дублирование, связность, читаемость. + +## Invariants +Что НЕ должно измениться: поведение, публичные API, форматы данных. + +## Acceptance criteria +- [ ] проверяемое условие (тесты зелёные, старый путь удалён, …) +``` + +## Template: `type/draft` + +A parking spot for ideas that are not fleshed out yet. Minimal structure, no +acceptance criteria required. Before implementation starts, a draft MUST be +promoted: relabeled to a concrete type and rewritten into that type's +template. + +```markdown +## Summary +Идея одним-двумя предложениями. + +## Spec +Ссылка или `none` (для драфтов обычно `none`). + +## Notes +Свободные заметки: что известно, открытые вопросы, варианты. +```