From 78015893d4fdfe7235a3ad8fc517900216d47f4a Mon Sep 17 00:00:00 2001 From: Defame1297 Date: Sun, 30 Aug 2026 12:28:54 +0000 Subject: [PATCH] refactor(gitea-issues): retrofit to the ADR-0020 context contract Description 827 -> 182 chars, body 902 -> 584 words, Gotchas 7 entries/43% of body -> 4/23.1%. Clears both size FAILs, the dangling-target FAIL and the Vale CompositionNote error. The dangling 'gitea-labels' target is gone with the composition sentence that carried it -- a YAML fold artifact, not a typo: the '>'-folded scalar joined 'gitea-labels-' and 'milestones' across a line break, leaving the name terminal and danglable. Both boundary names now sit whole on one source line each, and both resolve. Cut the second trigger register, the seven-verb capability enumeration, the issue_write implementation detail and a gitea-branches boundary that defended nothing. Two Gotchas deleted as spec restatement carried in references/, one as a paraphrase of the step below it. Closes a capability hole rather than papering over it: gitea-labels-milestones routes label application here and has no issue_write, but no dispatch row existed for add/replace/remove/clear_labels or get_labels. Both rows added. The label ID/name Gotcha is now stated per method -- issue_write takes IDs, list_issues and search_issues filter by name, issue_read 'get' returns names but 'get_labels' returns full objects with IDs. Drops a stale quotation of gitea-labels-milestones' description from references/enrichments.md; that string went with its composition note. Refs #99 --- .../gitea/.apm/skills/gitea-issues/README.md | 20 +++- .../gitea/.apm/skills/gitea-issues/SKILL.md | 92 ++++++------------- .../gitea-issues/references/enrichments.md | 3 +- .../skills/gitea-issues/references/sources.md | 4 +- 4 files changed, 48 insertions(+), 71 deletions(-) diff --git a/plugins/gitea/.apm/skills/gitea-issues/README.md b/plugins/gitea/.apm/skills/gitea-issues/README.md index 7d83306..adf34d8 100644 --- a/plugins/gitea/.apm/skills/gitea-issues/README.md +++ b/plugins/gitea/.apm/skills/gitea-issues/README.md @@ -18,9 +18,19 @@ the blocked `get_me` scope, and the "Depends on #N" dependency-linking conventio Requires a Gitea MCP server configured with a token holding `write:issue` + `write:repository`. Requires a git remote named `origin` pointing at the Gitea instance, unless an orchestrating caller -(e.g. `gitea-workflow`) already resolved `owner`/`repo` for you. Label and milestone management -(creating/editing a label, creating/closing a milestone) is out of scope here — that's -`gitea-labels-milestones`, which this skill composes rather than duplicates. +(e.g. `gitea-workflow`) already resolved `owner`/`repo` for you. + +## How it composes + +This skill composes `gitea-labels-milestones` for *all* label inference, label-name-to-ID +resolution, and milestone lookup, rather than duplicating that taxonomy or its resolution logic — +see `references/enrichments.md` for the call protocol. Managing the label and milestone definitions +themselves (create/edit/delete a label, create/close a milestone) is out of scope here and goes to +`gitea-labels-milestones` directly. + +One boundary the description does not spend characters on, because it was never going to win an +issue request: local git branch or commit work belongs to `gitea-branches` (Gitea-side) or +`git-branches` (working copy). ## Usage @@ -28,8 +38,8 @@ Requires a git remote named `origin` pointing at the Gitea instance, unless an o /gitea-issues ``` -Describe your task: list issues, create one, get/comment/close a specific issue number, or search -across repos. See `SKILL.md`'s dispatch table for the full set of recognized invocations. +Describe your task: list issues, create one, get/comment/close/label a specific issue number, or +search across repos. See `SKILL.md`'s dispatch table for the full set of recognized invocations. ## Files diff --git a/plugins/gitea/.apm/skills/gitea-issues/SKILL.md b/plugins/gitea/.apm/skills/gitea-issues/SKILL.md index 8cfc6fe..b168d4a 100644 --- a/plugins/gitea/.apm/skills/gitea-issues/SKILL.md +++ b/plugins/gitea/.apm/skills/gitea-issues/SKILL.md @@ -2,15 +2,9 @@ name: gitea-issues description: > - Use when reading or writing Gitea issues: listing repo issues, getting a single issue's details/ - comments/labels, creating an issue, updating its state, adding or editing comments, applying - labels via issue_write, or searching issues/PRs across repositories. Triggers on "create an - issue", "what issues are open", "get issue #N", "close issue #N", "comment on issue #N", "search - issues for X" — even when the user doesn't say "Gitea" explicitly. Composes gitea-labels- - milestones for all label inference/resolution and milestone lookup — do not use this skill to - manage label or milestone definitions themselves (create/edit/delete a label, create/close a - milestone), that's gitea-labels-milestones directly. Do not use for pull requests (use gitea-prs) - or for local git branch/commit work (use gitea-branches or git-branches). + Use when reading or writing Gitea issues — even when the user does not say "Gitea". + Not pull requests -> `gitea-prs`. + Not label or milestone definitions -> `gitea-labels-milestones`. compatibility: Requires Gitea MCP server configured with write:issue and write:repository token scopes. Requires git remote "origin" pointing to the Gitea instance for owner/repo resolution @@ -19,7 +13,7 @@ compatibility: Requires Gitea MCP server configured with write:issue and write:r metadata: category: integration - version: "0.1.0" + version: "0.1.3" source_keys: - gitea-mcp-repo - gitea-mcp-slim-go @@ -31,75 +25,49 @@ allowed-tools: Bash mcp__gitea__list_issues mcp__gitea__issue_read mcp__gitea__i ## Gotchas -- **`list_issues` has no `type` or `milestones` parameter — despite `api-reference.md` documenting both.** The live MCP schema (re-verified via `ToolSearch` at authoring time — see `references/sources.md`) only accepts `owner`, `repo` (required), `state` (default `"all"`), `labels` (array of label *names*), `since`, `before` (ISO 8601), `page`, `per_page` (default 30). This tool provides no way to filter issues-vs-PRs or by milestone. Since issues and PRs share one number space, `list_issues` results can include PR entries with no client-side filter to exclude them. If you need to know whether a specific number is a PR, call `issue_read method: "get"` and check `is_pull` — that field only appears on the single-item response, never in a list item. This exact drift (a prior skill trusted the research doc's `type` param and broke) is why this skill's reference files were re-verified live rather than copied from `api-reference.md`. -- **`search_issues` does have a working `type` filter** (`"issues"` | `"pulls"`) — unlike `list_issues`. Its `labels` parameter is also shaped differently: a comma-separated string, not an array of names. -- **Labels are numeric IDs on write, name strings on read.** `issue_write`'s `labels` parameter (used by `add_labels`/`replace_labels`) takes IDs. `list_issues`/`issue_read` return names. Never resolve this yourself — compose `gitea-labels-milestones` (see `references/enrichments.md`) to get IDs. -- **Milestone on `issue_read` is `{id, title}`** — an object, not a bare string. This skill only ever needs the `id`. (The bare-title-string case only happens on the PR side, which is `gitea-prs`' problem, not this skill's.) -- **Closing-keyword auto-close behavior is plausible but unconfirmed in our research docs.** Our research docs confirm Gitea does NOT auto-close an issue on a plain PR merge (unlike GitHub) — closing keywords like `Fixes #N`/`Closes #N` in a commit message are not documented one way or the other. After a PR merges (a `gitea-prs` operation), always re-check the issue's state here via `issue_read method: "get"` before deciding whether to close it manually — closing an already-closed issue is a harmless no-op, but don't assume a manual close is always needed. -- **Pagination is manual.** `list_issues` and `search_issues` return one page at a time. Iterate `page: 1, 2, ...` until the returned count is less than `per_page`. -- **HTTP 404 may actually mean 403.** Gitea hides permission errors as not-found. If a call 404s unexpectedly, verify the token holds `write:issue` scope (see `references/issues.md`'s Token scope note) before concluding the issue doesn't exist. +- **`list_issues` returns PRs too.** It has no `type` filter and both share one repo number space. `is_pull` appears only on `issue_read method: "get"`, never on a list item — check it there before treating a number as an issue. +- **Label IDs and names are not interchangeable.** `issue_write` takes numeric IDs only; `list_issues` and `search_issues` filter by name; `issue_read "get"` returns names but `"get_labels"` returns full objects with IDs. Resolve via `gitea-labels-milestones` unless the caller named exact labels. +- **A merged PR leaves its issue open.** Gitea does not auto-close on merge the way GitHub does. Re-read the issue's state after a merge before closing it manually. +- **A 404 may really be a 403.** Gitea hides permission errors as not-found — check the token's `write:issue` scope before concluding the issue does not exist. ## Step 1 — Resolve owner and repo -Before any tool call, extract `owner` and `repo` from the git remote (skip this if an orchestrating caller already passed them in): +An orchestrating caller may pass `owner` and `repo` in already; if so, skip this. The `search` row is cross-repository and needs only a query, so it skips this too. Otherwise, before any tool call: ```bash git remote get-url origin ``` -If origin is not set or the URL is not a Gitea URL, stop and report: "No Gitea remote found — set origin to your Gitea instance URL." +If origin is unset or the URL is not a Gitea URL, stop and report: "No Gitea remote found — set origin to your Gitea instance URL." ## Step 2 — Dispatch -| Invocation | Action | -|---|---| -| `/gitea-issues` or `/gitea-issues list` | List issues (optional state filter) | -| `/gitea-issues create` | Create an issue from conversation context — infers labels, checks milestone fit, applies a configured default assignee if set | -| `/gitea-issues ` | Get issue details (flag it as a PR if `is_pull: true`) | -| `/gitea-issues comments` | Get an issue's comments | -| `/gitea-issues close ` | Close an issue | -| `/gitea-issues comment ` | Add a comment from conversation context | -| `/gitea-issues search ` | Cross-repo search via `search_issues` | +One invocation takes one row. Read only the reference(s) that row names — the call signatures were verified against the live MCP schema and differ from the published API docs in ways the body does not restate. -For full parameter detail on `list_issues`/`issue_read`/`issue_write`, read `references/issues.md`. For `search_issues`, read `references/search.md`. For the create-flow enrichments (label inference, milestone assignment, assignee workaround, dependency-linking), read `references/enrichments.md`. +| Invocation | Flow | Read | +|---|---|---| +| `/gitea-issues` or `/gitea-issues list` | List issues, optionally filtered by state | `references/issues.md` | +| `/gitea-issues ` | Get one issue, routing to `gitea-prs` when the number turns out to be a PR | `references/issues.md` | +| `/gitea-issues comments` | Get an issue's comments | `references/issues.md` | +| `/gitea-issues labels` | Get an issue's labels as full objects, IDs included | `references/issues.md` | +| `/gitea-issues close ` | Close an issue by updating its state | `references/issues.md` | +| `/gitea-issues comment ` | Add a comment drawn from conversation context, never one invented to fill the gap — a comment on a live issue is not cheap to undo | `references/issues.md` | +| `/gitea-issues label ` | Apply, replace or remove labels using IDs resolved by `gitea-labels-milestones` | `references/issues.md` | +| `/gitea-issues create` | Create an issue — Step 3 first | `references/enrichments.md`, then `references/issues.md` | +| `/gitea-issues search ` | Cross-repo search, narrowed by owner, state, type or labels | `references/search.md` | -## Step 3 — Execute +## Step 3 — Create -### list (default) +Only the create flow reaches this step; every other row goes straight to its reference. -Call `list_issues owner: repo: state: <"open"|"closed"|"all", default "all">`. Remember: results may include PR entries (see Gotchas) — if the caller needs issues only, this tool cannot filter that server-side; note the limitation rather than silently mislabeling PR entries as issues. - -### create - -1. Extract `title` and `body` from conversation context (the most recent task, bug description, or explicit statement). Fall back to an empty body if nothing is available. -2. Run the enrichment sequence in `references/enrichments.md`: infer labels (composing `gitea-labels-milestones`), check for a clearly-fitting open milestone (composing the same skill), and check for a configured default assignee. -3. Call `issue_write method: "create" owner: repo: title: body: <body> labels: [<resolved IDs, or omit>] milestone: <resolved ID, or omit> assignees: [<default login, or omit>]`. -4. Fire immediately — no confirmation step for the create itself. - -### `<N>` (get) - -Call `issue_read method: "get" owner: <owner> repo: <repo> issue_number: <N>`. If `is_pull: true`, report that this number is actually a PR and suggest `gitea-prs` for full detail. - -### `<N> comments` - -Call `issue_read method: "get_comments" owner: <owner> repo: <repo> issue_number: <N>`. - -### close `<N>` - -Call `issue_write method: "update" owner: <owner> repo: <repo> issue_number: <N> state: "closed"`. No `method: "close"` exists. - -### comment `<N>` - -Extract the comment body from conversation context (same sourcing as create). Call `issue_write method: "add_comment" owner: <owner> repo: <repo> issue_number: <N> body: <body>`. - -### search `<query>` - -Call `search_issues query: <query>`, adding `owner`, `state`, `type`, or `labels` filters if the request narrows scope (e.g. "search open PRs for X" → `type: "pulls" state: "open"`). +1. Take `title` and `body` from conversation context — the most recent task, bug report, or explicit statement. An empty body is an acceptable fallback, an invented one is not. +2. Run the enrichments in `references/enrichments.md`, then create with the resolved IDs per `references/issues.md`. Omitting a parameter always beats guessing its value — a wrong milestone or assignee is harder to notice than a missing one. +3. Fire immediately, with no confirmation step. A create is cheap to undo by closing, so a gate here only costs a round trip. ## Step 4 — Report -For reads: a compact table or numbered list — number, title, state, labels, milestone. +Reads: a compact table or numbered list — number, title, state, labels, milestone. -For writes: confirm what was created/updated with the issue number and URL if returned. +Writes: what was created or updated, with the issue number and the URL when one is returned. -For errors: surface the HTTP code and message; check token scope per the Gotchas if a 404 looks wrong. +Errors: the HTTP code and message as returned, without paraphrasing either. diff --git a/plugins/gitea/.apm/skills/gitea-issues/references/enrichments.md b/plugins/gitea/.apm/skills/gitea-issues/references/enrichments.md index 09ae4ac..2977587 100644 --- a/plugins/gitea/.apm/skills/gitea-issues/references/enrichments.md +++ b/plugins/gitea/.apm/skills/gitea-issues/references/enrichments.md @@ -19,8 +19,7 @@ plausibly fits). reference files directly by path. A plugin install copies each skill's directory into an isolated cache — any file path that leaves this skill's own directory breaks post-install. Instead, compose `gitea-labels-milestones` as a skill: describe the task to it (its own `SKILL.md` and description -trigger it) and consume the resolved IDs it returns. This mirrors how `gitea-labels-milestones`'s -own description already frames the relationship ("`gitea-issues` and `gitea-prs` both compose it"). +trigger it) and consume the resolved IDs it returns. ## 1. Label inference diff --git a/plugins/gitea/.apm/skills/gitea-issues/references/sources.md b/plugins/gitea/.apm/skills/gitea-issues/references/sources.md index 65b6516..904be31 100644 --- a/plugins/gitea/.apm/skills/gitea-issues/references/sources.md +++ b/plugins/gitea/.apm/skills/gitea-issues/references/sources.md @@ -5,8 +5,8 @@ signatures in `references/issues.md` and `references/search.md` were re-verified `ToolSearch` against the deployed `gitea-mcp` server at authoring time — they are not copied verbatim from `api-reference.md`. This resolves issue #6 comment #849's root-cause finding that a prior skill was authored from API docs that had drifted from the actual MCP tool schema; the live -check caught exactly this drift on `list_issues` (see SKILL.md Gotchas — the research doc documents -a `type` and a `milestones` parameter that do not exist on the deployed server). +check caught exactly this drift on `list_issues` (see `references/issues.md` — the research doc +documents a `type` and a `milestones` parameter that do not exist on the deployed server). ## gitea-mcp-repo