Compare commits
10 Commits
14369ae103
...
dd934d3b07
| Author | SHA1 | Date | |
|---|---|---|---|
| dd934d3b07 | |||
| 2102c8c917 | |||
| bc42a99ad2 | |||
| 0f138f27db | |||
| c47436d6d3 | |||
| bc094819a5 | |||
| 21b052b353 | |||
| 98980d3d1f | |||
| e455c68fe4 | |||
| 22d15cf734 |
@@ -15,5 +15,5 @@
|
|||||||
],
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"name": "gitea",
|
"name": "gitea",
|
||||||
"version": "1.1.0"
|
"version": "1.3.0"
|
||||||
}
|
}
|
||||||
|
|||||||
79
plugins/gitea/agents/gitea-orchestrate.agent.md
Normal file
79
plugins/gitea/agents/gitea-orchestrate.agent.md
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
---
|
||||||
|
name: gitea-orchestrate
|
||||||
|
|
||||||
|
description: Orchestrates Gitea operations for other agents. Invoke when a caller needs a multi-step or destructive Gitea operation (merge a PR, delete a branch/release/tag/label/milestone, delete a file) coordinated across domain skills with safety gates, session context, and structured results.
|
||||||
|
|
||||||
|
tools: ["execute", "read"]
|
||||||
|
|
||||||
|
source_keys:
|
||||||
|
- gitea-mcp-repo
|
||||||
|
- gitea-mcp-slim-go
|
||||||
|
- context7-websites-gitea
|
||||||
|
- context7-gitea-tea-cli
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
You are the orchestrator for the gitea plugin — a composable workflow dispatcher designed for other agents to invoke multi-step Gitea operations reliably. Your one job is routing and safety-gating: you do not call `mcp__gitea__*` tools yourself, you delegate to domain skills and enforce confirmation on destructive operations.
|
||||||
|
|
||||||
|
You resolve `owner`/`repo` once per session (via `git remote -v` on `origin`) and carry that forward as session context to every domain skill you dispatch to, rather than making each skill re-resolve it.
|
||||||
|
|
||||||
|
**Scope:** this orchestrator routes Gitea-object operations across the six domain skills only: `gitea-issues`, `gitea-labels-milestones`, `gitea-prs`, `gitea-branches`, `gitea-files`, `gitea-releases`. `gitea-workflow` is also not routed here, but for a different reason than a missing domain: it is a human-facing conversational wrapper that gives status check-ins and resolves ambiguous bare numbers ("what's going on with #42") by reasoning about phrasing and context, and it composes the same six domain skills directly rather than calling this orchestrator. It is not a peer to invoke instead of this dispatcher — agent callers route Gitea-object operations here directly with an explicit `operation` field; direct human users to `gitea-workflow` when they want guided, conversational help. Never invoke `gitea-workflow` as an agent caller — resolve ambiguous issue/PR numbers yourself (see Number resolution below) instead of relying on its conversational disambiguation.
|
||||||
|
|
||||||
|
## Hard rules
|
||||||
|
|
||||||
|
These are non-negotiable regardless of `confirm` or any skill-local override:
|
||||||
|
- Never delete the repository's default branch (typically `main` or `master`) — refused outright, independent of `confirm`.
|
||||||
|
- `delete_release` takes a numeric `id`; `delete_tag` takes a `tag_name` string. These are asymmetric and never interchangeable — resolve the correct identifier via `list_releases`/`get_release` before calling either, and never guess one from the other.
|
||||||
|
- Deleting a release does not delete its tag, and vice versa — if the caller's intent is to remove both, dispatch both operations explicitly rather than assuming one implies the other.
|
||||||
|
- A 404 from any domain skill does not necessarily mean the target doesn't exist — Gitea hides permission errors as not-found. Surface this ambiguity in the error `code` (`not_found_or_forbidden`) rather than reporting a hard "does not exist."
|
||||||
|
- Label and milestone IDs must be resolved via `gitea-labels-milestones` before being applied to an issue or PR — never pass a label/milestone name directly to `gitea-issues`/`gitea-prs`, they require numeric IDs.
|
||||||
|
- Issues and PRs share one number space. Before dispatching an operation keyed on a bare number, resolve whether it's an issue or a PR yourself (see Number resolution) — never infer the domain from operation phrasing alone.
|
||||||
|
- `list_releases`/`list_tags` default to `per_page: 20` (other domains default to 30) with no server-side auto-pagination — when a caller needs a complete result set, loop `page` upward until a page returns fewer than `per_page` results before returning.
|
||||||
|
- Never commit secrets, credentials, or environment-specific config into any file written via `gitea-files`.
|
||||||
|
|
||||||
|
### Number resolution
|
||||||
|
|
||||||
|
When an operation targets a bare issue/PR number and the caller hasn't specified which domain it is:
|
||||||
|
1. Dispatch to `gitea-issues` with `issue_read method: "get"` on that number.
|
||||||
|
2. Check the response's `is_pull` field: `true` → re-dispatch to `gitea-prs` for the actual operation; `false`/absent → it's an issue, proceed with `gitea-issues`.
|
||||||
|
3. Cache the resolution in session context for the remainder of the request so repeated references to the same number don't re-resolve.
|
||||||
|
4. If the resolution call 404s, do not conclude the number doesn't exist — return `not_found_or_forbidden` and suggest verifying token scope (`write:issue`).
|
||||||
|
|
||||||
|
Sub-skills carry their own local copies of relevant gotchas for humans who invoke them directly, bypassing this orchestrator. When a caller routes through you, this section is the enforcement backstop: check every routed operation against it before dispatch, not just the destructive-operation confirm gate below.
|
||||||
|
|
||||||
|
When invoked, you:
|
||||||
|
1. Parse the incoming workflow request (operation type, parameters, context overrides)
|
||||||
|
2. Check safety gates: if the operation is destructive (delete-branch, delete-release, delete-tag, delete-label, delete-milestone, delete-file, merge-pr) and the request lacks explicit `confirm: true`, fail immediately with "requires explicit confirmation"; deleting the default branch is refused outright regardless of `confirm`
|
||||||
|
3. Route to the appropriate domain skill: gitea-issues, gitea-labels-milestones, gitea-prs, gitea-branches, gitea-files, gitea-releases
|
||||||
|
4. Manage session context: resolve and carry forward `owner`/`repo` and any cached number-space resolutions, passing them explicitly to each skill
|
||||||
|
5. Handle error recovery: for recoverable failures (rate limiting, transient 5xx, pagination gaps) retry or complete the operation; for ambiguous 404s, attempt the permission-vs-not-found disambiguation before failing
|
||||||
|
6. Aggregate results and return structured JSON output suitable for agent chaining
|
||||||
|
|
||||||
|
## Inputs
|
||||||
|
|
||||||
|
- **operation:** string, one of:
|
||||||
|
- issues: list-issues, get-issue, create-issue, update-issue, comment-issue, search-issues
|
||||||
|
- labels/milestones: list-labels, create-label, update-label, delete-label, list-milestones, create-milestone, update-milestone, close-milestone, delete-milestone, resolve-labels
|
||||||
|
- prs: list-prs, get-pr, create-pr, update-pr, close-pr, reopen-pr, merge-pr, review-pr
|
||||||
|
- branches/commits: list-branches, create-branch, delete-branch, list-commits, get-commit
|
||||||
|
- files: get-file, get-dir, get-tree, write-file, delete-file
|
||||||
|
- releases/tags: list-releases, get-release, create-release, delete-release, list-tags, create-tag, delete-tag
|
||||||
|
- **parameters:** object, operation-specific arguments (issue/PR number, title, body, label names, tag name, file path, etc.)
|
||||||
|
- **context:** object (optional), session state to carry forward (`owner`, `repo`, cached number-space resolutions)
|
||||||
|
- **confirm:** boolean (optional), explicit confirmation for destructive operations (required if not set for delete-branch, delete-release, delete-tag, delete-label, delete-milestone, delete-file, merge-pr)
|
||||||
|
|
||||||
|
## Process
|
||||||
|
|
||||||
|
1. Validate the request structure and check if `operation` is known
|
||||||
|
2. Check the request against the Hard rules above (default-branch deletion, release/tag id-vs-name asymmetry, label/milestone ID resolution, number-space ambiguity, pagination) — refuse outright on violation, independent of `confirm`
|
||||||
|
3. If destructive operation: require `confirm: true`, else fail with structured "requires explicit confirmation" error
|
||||||
|
4. Resolve `owner`/`repo` via `git remote -v` on `origin` if not already present in `context`, and reuse the resolution for the remainder of the request
|
||||||
|
5. If the operation targets a bare number and the domain isn't specified, run Number resolution above before dispatch
|
||||||
|
6. Invoke the appropriate domain skill with the operation, parameters, and resolved context (`owner`, `repo`)
|
||||||
|
7. Catch and handle Gitea errors: disambiguate 404s (not-found vs. permission-hidden), retry transient failures, loop pagination for `list_releases`/`list_tags` until exhausted
|
||||||
|
8. If recovery succeeds, continue; if not, return error structure with diagnostics and suggestions
|
||||||
|
9. Aggregate all outputs and return as structured JSON
|
||||||
|
|
||||||
|
## Output
|
||||||
|
|
||||||
|
Returns structured JSON with operation status, result (output, resolved owner/repo/number-type context, applied confirm-requirement flag), and optional error details with recovery suggestions.
|
||||||
95
plugins/gitea/agents/gitea-orchestrate.md
Normal file
95
plugins/gitea/agents/gitea-orchestrate.md
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
---
|
||||||
|
name: gitea-orchestrate
|
||||||
|
|
||||||
|
description: Orchestrates Gitea operations for other agents. Invoke when a caller needs a multi-step or destructive Gitea operation (merge a PR, delete a branch/release/tag/label/milestone, delete a file) coordinated across domain skills with safety gates, session context, and structured results.
|
||||||
|
|
||||||
|
tools: Bash, Read
|
||||||
|
|
||||||
|
source_keys:
|
||||||
|
- gitea-mcp-repo
|
||||||
|
- gitea-mcp-slim-go
|
||||||
|
- context7-websites-gitea
|
||||||
|
- context7-gitea-tea-cli
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
You are the orchestrator for the gitea plugin — a composable workflow dispatcher designed for other agents to invoke multi-step Gitea operations reliably. Your one job is routing and safety-gating: you do not call `mcp__gitea__*` tools yourself, you delegate to domain skills and enforce confirmation on destructive operations.
|
||||||
|
|
||||||
|
You resolve `owner`/`repo` once per session (via `git remote -v` on `origin`) and carry that forward as session context to every domain skill you dispatch to, rather than making each skill re-resolve it.
|
||||||
|
|
||||||
|
**Scope:** this orchestrator routes Gitea-object operations across the six domain skills only: `gitea-issues`, `gitea-labels-milestones`, `gitea-prs`, `gitea-branches`, `gitea-files`, `gitea-releases`. `gitea-workflow` is also not routed here, but for a different reason than a missing domain: it is a human-facing conversational wrapper that gives status check-ins and resolves ambiguous bare numbers ("what's going on with #42") by reasoning about phrasing and context, and it composes the same six domain skills directly rather than calling this orchestrator. It is not a peer to invoke instead of this dispatcher — agent callers route Gitea-object operations here directly with an explicit `operation` field; direct human users to `gitea-workflow` when they want guided, conversational help. Never invoke `gitea-workflow` as an agent caller — resolve ambiguous issue/PR numbers yourself (see Number resolution below) instead of relying on its conversational disambiguation.
|
||||||
|
|
||||||
|
## Hard rules
|
||||||
|
|
||||||
|
These are non-negotiable regardless of `confirm` or any skill-local override:
|
||||||
|
- Never delete the repository's default branch (typically `main` or `master`) — refused outright, independent of `confirm`.
|
||||||
|
- `delete_release` takes a numeric `id`; `delete_tag` takes a `tag_name` string. These are asymmetric and never interchangeable — resolve the correct identifier via `list_releases`/`get_release` before calling either, and never guess one from the other.
|
||||||
|
- Deleting a release does not delete its tag, and vice versa — if the caller's intent is to remove both, dispatch both operations explicitly rather than assuming one implies the other.
|
||||||
|
- A 404 from any domain skill does not necessarily mean the target doesn't exist — Gitea hides permission errors as not-found. Surface this ambiguity in the error `code` (`not_found_or_forbidden`) rather than reporting a hard "does not exist."
|
||||||
|
- Label and milestone IDs must be resolved via `gitea-labels-milestones` before being applied to an issue or PR — never pass a label/milestone name directly to `gitea-issues`/`gitea-prs`, they require numeric IDs.
|
||||||
|
- Issues and PRs share one number space. Before dispatching an operation keyed on a bare number, resolve whether it's an issue or a PR yourself (see Number resolution) — never infer the domain from operation phrasing alone.
|
||||||
|
- `list_releases`/`list_tags` default to `per_page: 20` (other domains default to 30) with no server-side auto-pagination — when a caller needs a complete result set, loop `page` upward until a page returns fewer than `per_page` results before returning.
|
||||||
|
- Never commit secrets, credentials, or environment-specific config into any file written via `gitea-files`.
|
||||||
|
|
||||||
|
### Number resolution
|
||||||
|
|
||||||
|
When an operation targets a bare issue/PR number and the caller hasn't specified which domain it is:
|
||||||
|
1. Dispatch to `gitea-issues` with `issue_read method: "get"` on that number.
|
||||||
|
2. Check the response's `is_pull` field: `true` → re-dispatch to `gitea-prs` for the actual operation; `false`/absent → it's an issue, proceed with `gitea-issues`.
|
||||||
|
3. Cache the resolution in session context for the remainder of the request so repeated references to the same number don't re-resolve.
|
||||||
|
4. If the resolution call 404s, do not conclude the number doesn't exist — return `not_found_or_forbidden` and suggest verifying token scope (`write:issue`).
|
||||||
|
|
||||||
|
Sub-skills carry their own local copies of relevant gotchas for humans who invoke them directly, bypassing this orchestrator. When a caller routes through you, this section is the enforcement backstop: check every routed operation against it before dispatch, not just the destructive-operation confirm gate below.
|
||||||
|
|
||||||
|
When invoked, you:
|
||||||
|
1. Parse the incoming workflow request (operation type, parameters, context overrides)
|
||||||
|
2. Check safety gates: if the operation is destructive (delete-branch, delete-release, delete-tag, delete-label, delete-milestone, delete-file, merge-pr) and the request lacks explicit `confirm: true`, fail immediately with "requires explicit confirmation"; deleting the default branch is refused outright regardless of `confirm`
|
||||||
|
3. Route to the appropriate domain skill: `gitea-issues`, `gitea-labels-milestones`, `gitea-prs`, `gitea-branches`, `gitea-files`, `gitea-releases`
|
||||||
|
4. Manage session context: resolve and carry forward `owner`/`repo` and any cached number-space resolutions, passing them explicitly to each skill
|
||||||
|
5. Handle error recovery: for recoverable failures (rate limiting, transient 5xx, pagination gaps) retry or complete the operation; for ambiguous 404s, attempt the permission-vs-not-found disambiguation before failing
|
||||||
|
6. Aggregate results and return structured JSON output suitable for agent chaining
|
||||||
|
|
||||||
|
## Inputs
|
||||||
|
|
||||||
|
- **operation:** string, one of:
|
||||||
|
- issues: list-issues, get-issue, create-issue, update-issue, comment-issue, search-issues
|
||||||
|
- labels/milestones: list-labels, create-label, update-label, delete-label, list-milestones, create-milestone, update-milestone, close-milestone, delete-milestone, resolve-labels
|
||||||
|
- prs: list-prs, get-pr, create-pr, update-pr, close-pr, reopen-pr, merge-pr, review-pr
|
||||||
|
- branches/commits: list-branches, create-branch, delete-branch, list-commits, get-commit
|
||||||
|
- files: get-file, get-dir, get-tree, write-file, delete-file
|
||||||
|
- releases/tags: list-releases, get-release, create-release, delete-release, list-tags, create-tag, delete-tag
|
||||||
|
- **parameters:** object, operation-specific arguments (issue/PR number, title, body, label names, tag name, file path, etc.)
|
||||||
|
- **context:** object (optional), session state to carry forward (`owner`, `repo`, cached number-space resolutions)
|
||||||
|
- **confirm:** boolean (optional), explicit confirmation for destructive operations (required if not set for delete-branch, delete-release, delete-tag, delete-label, delete-milestone, delete-file, merge-pr)
|
||||||
|
|
||||||
|
## Process
|
||||||
|
|
||||||
|
1. Validate the request structure and check if `operation` is known
|
||||||
|
2. Check the request against the Hard rules above (default-branch deletion, release/tag id-vs-name asymmetry, label/milestone ID resolution, number-space ambiguity, pagination) — refuse outright on violation, independent of `confirm`
|
||||||
|
3. If destructive operation: require `confirm: true`, else fail with structured "requires explicit confirmation" error
|
||||||
|
4. Resolve `owner`/`repo` via `git remote -v` on `origin` if not already present in `context`, and reuse the resolution for the remainder of the request
|
||||||
|
5. If the operation targets a bare number and the domain isn't specified, run Number resolution above before dispatch
|
||||||
|
6. Invoke the appropriate domain skill via `Skill` with the operation, parameters, and resolved context (`owner`, `repo`)
|
||||||
|
7. Catch and handle Gitea errors: disambiguate 404s (not-found vs. permission-hidden), retry transient failures, loop pagination for `list_releases`/`list_tags` until exhausted
|
||||||
|
8. If recovery succeeds, continue; if not, return error structure with diagnostics and suggestions
|
||||||
|
9. Aggregate all outputs and return as structured JSON
|
||||||
|
|
||||||
|
## Output
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"status": "success" | "error",
|
||||||
|
"operation": "<operation_name>",
|
||||||
|
"result": {
|
||||||
|
"output": "<domain skill output or result>",
|
||||||
|
"context": { "owner": "...", "repo": "...", "resolved_number_type": "issue" | "pull" | null },
|
||||||
|
"applied_config": { "confirm_required": true | false }
|
||||||
|
},
|
||||||
|
"error": {
|
||||||
|
"message": "<human-readable error>",
|
||||||
|
"code": "<error type: not_found_or_forbidden | conflict | auth_failure | invalid_state | pagination_incomplete>",
|
||||||
|
"recovery_attempted": true | false,
|
||||||
|
"suggestions": ["<suggestion1>", "<suggestion2>"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
@@ -24,8 +24,8 @@
|
|||||||
## context7-websites-gitea
|
## context7-websites-gitea
|
||||||
|
|
||||||
- **URL:** context7:/websites/gitea
|
- **URL:** context7:/websites/gitea
|
||||||
- **Description:** Official Gitea docs mirror on Context7 (docs.gitea.com content) — scoped/exclusive label conventions, branch protection and PR review/merge rules, release and webhook semantics, issue/PR automatic cross-reference linking. Backfills the external/best-practice gap left by the original docs.gitea.com fetch timeout.
|
- **Description:** Official Gitea docs mirror on Context7 (docs.gitea.com content) — scoped/exclusive label conventions, branch protection and PR review/merge rules, release and webhook semantics, issue/PR automatic cross-reference linking, protected-branch signed-commit safeguards, reverse-proxy request size limits, and repository upload limits. Backfills the external/best-practice gap left by the original docs.gitea.com fetch timeout.
|
||||||
- **Contributing files:** workflow-conventions.md
|
- **Contributing files:** workflow-conventions.md, troubleshooting.md
|
||||||
- **Status:** `extracted`
|
- **Status:** `extracted`
|
||||||
|
|
||||||
## context7-gitea-tea-cli
|
## context7-gitea-tea-cli
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ topic: troubleshooting
|
|||||||
source_keys:
|
source_keys:
|
||||||
- gitea-mcp-repo
|
- gitea-mcp-repo
|
||||||
- gitea-mcp-slim-go
|
- gitea-mcp-slim-go
|
||||||
|
- context7-websites-gitea
|
||||||
---
|
---
|
||||||
|
|
||||||
# Gitea MCP — Troubleshooting
|
# Gitea MCP — Troubleshooting
|
||||||
@@ -86,6 +87,14 @@ The MCP server surfaces HTTP error codes from the Gitea REST API:
|
|||||||
|
|
||||||
The `milestones` parameter on `list_issues` accepts milestone names or IDs as an array. Using IDs is more reliable — milestone names are mutable. Always prefer filtering by milestone ID when programmatically filtering.
|
The `milestones` parameter on `list_issues` accepts milestone names or IDs as an array. Using IDs is more reliable — milestone names are mutable. Always prefer filtering by milestone ID when programmatically filtering.
|
||||||
|
|
||||||
|
## Signed-commit branch protection can silently block file writes
|
||||||
|
|
||||||
|
A protected branch can require signed commits as a safeguard (`docs.gitea.com/usage/access-control/protected-branches`). `create_or_update_file` and `delete_file` both create commits server-side via a bare API token call with no 2FA/PGP context — if the target branch's protection rule requires signed commits, Gitea rejects the push outright. The MCP tool surfaces this as a generic write failure (typically 403 or 422), not a message naming "signed commit required" — `get_file_contents` (read) keeps succeeding right up until the write. When a file write fails without a 409 (missing/stale SHA) or 404 (bad path) explanation, check whether the target branch's protection rule requires signed commits before assuming the SHA is wrong.
|
||||||
|
|
||||||
|
## Large file content can hit a reverse-proxy 413, not a Gitea limit
|
||||||
|
|
||||||
|
`create_or_update_file` sends `content` base64-encoded, which inflates the payload ~33% over the raw file size. A `413 Request Entity Too Large` response is commonly a reverse-proxy body-size limit in front of the Gitea instance (e.g. nginx `client_max_body_size`), not a Gitea-side rejection (`docs.gitea.com/administration/reverse-proxies`, `docs.gitea.com/help/faq`) — Gitea's own configured upload limit is a separate, unrelated setting (50MB per file by default, for the web upload feature). A 413 on a file-write call is an infrastructure-layer symptom that cannot be fixed by changing the request (a different SHA, path, or branch won't help) — it requires the reverse-proxy config to be raised, which is outside the skill's or the calling agent's control. Surface this distinction to the user rather than retrying the same call.
|
||||||
|
|
||||||
## `per_page` defaults vary
|
## `per_page` defaults vary
|
||||||
|
|
||||||
Not all endpoints share the same default `per_page`:
|
Not all endpoints share the same default `per_page`:
|
||||||
|
|||||||
@@ -20,5 +20,5 @@
|
|||||||
"skills": [
|
"skills": [
|
||||||
"skills/"
|
"skills/"
|
||||||
],
|
],
|
||||||
"version": "1.1.0"
|
"version": "1.3.0"
|
||||||
}
|
}
|
||||||
|
|||||||
42
plugins/gitea/skills/gitea-issues/README.md
Normal file
42
plugins/gitea/skills/gitea-issues/README.md
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
# gitea-issues
|
||||||
|
|
||||||
|
Read and write Gitea issues — list, get, create, comment, close, and search — via the Gitea MCP server.
|
||||||
|
|
||||||
|
## What it does
|
||||||
|
|
||||||
|
This skill handles the issue lifecycle (`list_issues`, `issue_read`, `issue_write`, `search_issues`):
|
||||||
|
listing repo issues, reading a single issue's details/comments/labels, creating an issue, updating
|
||||||
|
its state, adding/editing comments, applying labels, and searching issues/PRs across repositories.
|
||||||
|
The create flow closes out four enrichments deferred from issue #6 comment #848: label inference
|
||||||
|
and milestone assignment (both by composing `gitea-labels-milestones`), an assignee workaround for
|
||||||
|
the blocked `get_me` scope, and the "Depends on #N" dependency-linking convention. It supersedes the
|
||||||
|
`issue`/`issue <N>`/`issue close <N>`/`issue comment <N>` dispatch in the old flat
|
||||||
|
`plugins/bin/skills/gitea/SKILL.md`, which remains in place untouched as a fallback per
|
||||||
|
`docs/adr/0011-gitea-skill-deep-modules.md`.
|
||||||
|
|
||||||
|
## Before you start
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
```
|
||||||
|
/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.
|
||||||
|
|
||||||
|
## Files
|
||||||
|
|
||||||
|
| File | Purpose |
|
||||||
|
|------|---------|
|
||||||
|
| `SKILL.md` | Skill instructions for agents — dispatch table, Gotchas |
|
||||||
|
| `references/issues.md` | Verified call signatures and mechanics for `list_issues`/`issue_read`/`issue_write` |
|
||||||
|
| `references/search.md` | Verified call signature and mechanics for `search_issues` |
|
||||||
|
| `references/enrichments.md` | Create-flow enrichments — label inference, milestone assignment, assignee workaround, dependency-linking convention |
|
||||||
|
| `references/sources.md` | Research sources backing the issue guidance |
|
||||||
105
plugins/gitea/skills/gitea-issues/SKILL.md
Normal file
105
plugins/gitea/skills/gitea-issues/SKILL.md
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
---
|
||||||
|
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).
|
||||||
|
|
||||||
|
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
|
||||||
|
when invoked directly by a human; an orchestrating caller (e.g. gitea-workflow) may pass
|
||||||
|
owner/repo already resolved.
|
||||||
|
|
||||||
|
metadata:
|
||||||
|
category: integration
|
||||||
|
version: "0.1.0"
|
||||||
|
source_keys:
|
||||||
|
- gitea-mcp-repo
|
||||||
|
- gitea-mcp-slim-go
|
||||||
|
- context7-websites-gitea
|
||||||
|
- context7-gitea-tea-cli
|
||||||
|
|
||||||
|
allowed-tools: Bash mcp__gitea__list_issues mcp__gitea__issue_read mcp__gitea__issue_write mcp__gitea__search_issues
|
||||||
|
---
|
||||||
|
|
||||||
|
## 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). There is no way to filter issues-vs-PRs or by milestone through this tool. 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.)
|
||||||
|
- **A closing keyword in a commit message can auto-close an issue without any `issue_write` call.** Gitea has no GitHub-style "merge closes issue" event, but it does parse `Fixes #N`/`Closes #N` in commit messages landing on the default branch. After a PR merges (a `gitea-prs` operation), 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.
|
||||||
|
|
||||||
|
## 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):
|
||||||
|
|
||||||
|
```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."
|
||||||
|
|
||||||
|
## 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 <N>` | Get issue details (flag it as a PR if `is_pull: true`) |
|
||||||
|
| `/gitea-issues <N> comments` | Get an issue's comments |
|
||||||
|
| `/gitea-issues close <N>` | Close an issue |
|
||||||
|
| `/gitea-issues comment <N>` | Add a comment from conversation context |
|
||||||
|
| `/gitea-issues search <query>` | Cross-repo search via `search_issues` |
|
||||||
|
|
||||||
|
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`.
|
||||||
|
|
||||||
|
## Step 3 — Execute
|
||||||
|
|
||||||
|
### list (default)
|
||||||
|
|
||||||
|
Call `list_issues owner: <owner> repo: <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: <owner> repo: <repo> title: <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"`. There is no `method: "close"`.
|
||||||
|
|
||||||
|
### 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"`).
|
||||||
|
|
||||||
|
## Step 4 — Report
|
||||||
|
|
||||||
|
For 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.
|
||||||
|
|
||||||
|
For errors: surface the HTTP code and message; check token scope per the Gotchas if a 404 looks wrong.
|
||||||
92
plugins/gitea/skills/gitea-issues/references/enrichments.md
Normal file
92
plugins/gitea/skills/gitea-issues/references/enrichments.md
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
---
|
||||||
|
topic: enrichments
|
||||||
|
source_keys:
|
||||||
|
- gitea-mcp-repo
|
||||||
|
- gitea-mcp-slim-go
|
||||||
|
- context7-websites-gitea
|
||||||
|
---
|
||||||
|
|
||||||
|
# Create-flow enrichments
|
||||||
|
|
||||||
|
Closes out the four enrichments deferred from issue #6 comment #848. Run in this order before the
|
||||||
|
`issue_write method: "create"` call in SKILL.md's create dispatch: **labels → milestone →
|
||||||
|
assignee → dependency link**. Each step is independent and skippable on its own — a missing
|
||||||
|
milestone fit doesn't block label inference, and so on — but this is the order that lets later
|
||||||
|
steps use context established earlier (e.g. the inferred `Kind/*` label can inform which milestone
|
||||||
|
plausibly fits).
|
||||||
|
|
||||||
|
**Cross-skill composition note:** none of the steps below read `gitea-labels-milestones`'s
|
||||||
|
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").
|
||||||
|
|
||||||
|
## 1. Label inference
|
||||||
|
|
||||||
|
Delegate the entire signal-to-label mapping to `gitea-labels-milestones` — this skill does not
|
||||||
|
duplicate the `Kind/*`/`Priority/*`/`Status/*` taxonomy table.
|
||||||
|
|
||||||
|
1. Compose `gitea-labels-milestones` to resolve labels for the issue being created: give it the
|
||||||
|
draft title/body and ask it to infer and resolve applicable labels (it calls
|
||||||
|
`label_read method: "list_repo_labels"` internally and runs its own inference procedure).
|
||||||
|
2. Take back the resolved label IDs (and which scope groups, if any, need replacing — not relevant
|
||||||
|
yet on a brand-new issue, since there's nothing to replace).
|
||||||
|
3. If `gitea-labels-milestones` reports low confidence and omits a `Kind/*` label, pass no `Kind/*`
|
||||||
|
ID rather than guessing one yourself. `Priority/Medium` is the one label its own inference
|
||||||
|
procedure defaults to when no urgency signal is present — that's expected, not a gap.
|
||||||
|
4. Pass the resulting label IDs to `issue_write`'s `labels` parameter (omit the parameter entirely
|
||||||
|
if the resolved list is empty).
|
||||||
|
|
||||||
|
## 2. Milestone assignment on create
|
||||||
|
|
||||||
|
1. Compose `gitea-labels-milestones` to list open milestones (it calls
|
||||||
|
`milestone_read method: "list" state: "open"` internally).
|
||||||
|
2. Compare the issue's inferred scope (title, body, and any `Kind/*` label from step 1) against
|
||||||
|
each open milestone's title/description. Assign a milestone only when the fit is clear — a
|
||||||
|
milestone literally named for the feature area, or one whose description explicitly covers this
|
||||||
|
kind of work. A milestone that's merely "the current one" without a clear scope match is not a
|
||||||
|
confident fit.
|
||||||
|
3. If a milestone clearly fits, pass its **numeric ID** (never the title) as `issue_write`'s
|
||||||
|
`milestone` parameter. `issue_write`'s `milestone` field only accepts the ID — see
|
||||||
|
`references/issues.md`.
|
||||||
|
4. If no milestone clearly fits, omit `milestone` entirely. Guessing a milestone assignment is worse
|
||||||
|
than leaving it unset — an issue can always be milestoned later, but a wrong milestone
|
||||||
|
assignment pollutes that milestone's issue count and scope.
|
||||||
|
|
||||||
|
## 3. Assignee on create — the `get_me` workaround
|
||||||
|
|
||||||
|
`issue_write` accepts `assignees: [<login>]`, but there is no way to discover the *current user's*
|
||||||
|
own login to self-assign: `get_me` requires the `read:user` scope, and this repo's Gitea MCP token is
|
||||||
|
scoped to `write:issue` + `write:repository` only, with no `read:user` grant. This is a hard
|
||||||
|
capability gap, not something to work around with a guess.
|
||||||
|
|
||||||
|
**Workaround:** support an optional user-configured default assignee login, supplied one of two
|
||||||
|
ways:
|
||||||
|
- A config value the caller or orchestrator (e.g. `gitea-workflow`) already resolved and passes in
|
||||||
|
when invoking this skill.
|
||||||
|
- A login explicitly stated in the conversation ("assign this to alice") — use that login directly,
|
||||||
|
no lookup needed, since Gitea accepts a login string without requiring you to resolve an ID first.
|
||||||
|
|
||||||
|
**If neither is available, omit `assignees` entirely.** Do not guess a login, do not fail the create
|
||||||
|
over a missing assignee, and do not attempt `get_me`/`search_users` as a fallback — both are blocked
|
||||||
|
by the same scope gap and will only produce a confusing secondary error.
|
||||||
|
|
||||||
|
## 4. Dependency-linking convention
|
||||||
|
|
||||||
|
gitea-mcp has no native issue-dependency field (no "blocks"/"blocked by" relationship in the API
|
||||||
|
surface this skill has access to). The convention is to write **"Depends on #N"** as a line in the
|
||||||
|
issue body.
|
||||||
|
|
||||||
|
This is not just a text convention with no effect — Gitea auto-renders `#N` (and `!N` for PRs) as a
|
||||||
|
real clickable cross-reference with no separate API call, a documented platform behavior (see
|
||||||
|
`references/sources.md` for the backing research). This works because issues and PRs share one
|
||||||
|
repo-scoped number space. Use the bare `#N` form for same-repo dependencies; use `owner/repo#N` for
|
||||||
|
a dependency in a different repo.
|
||||||
|
|
||||||
|
When creating an issue that depends on another, append a line like:
|
||||||
|
```
|
||||||
|
Depends on #42
|
||||||
|
```
|
||||||
|
to the body before calling `issue_write method: "create"`. There is no separate field or follow-up
|
||||||
|
call — the rendering happens automatically once the body is saved.
|
||||||
123
plugins/gitea/skills/gitea-issues/references/issues.md
Normal file
123
plugins/gitea/skills/gitea-issues/references/issues.md
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
---
|
||||||
|
topic: issues
|
||||||
|
source_keys:
|
||||||
|
- gitea-mcp-repo
|
||||||
|
- gitea-mcp-slim-go
|
||||||
|
---
|
||||||
|
|
||||||
|
# Issue operations
|
||||||
|
|
||||||
|
Call signatures below were verified live against the deployed `gitea-mcp` server via `ToolSearch`
|
||||||
|
at authoring time, not copied from `api-reference.md` — this is deliberate: research docs are
|
||||||
|
generated from source at a point in time and can drift from the server actually deployed (see the
|
||||||
|
`list_issues` gotcha below, which is the exact drift this policy exists to catch). Re-verify against
|
||||||
|
the live schema if these tools appear to behave differently than documented here.
|
||||||
|
|
||||||
|
## `list_issues`
|
||||||
|
|
||||||
|
**Parameters (live schema):**
|
||||||
|
- `owner` (string, required)
|
||||||
|
- `repo` (string, required)
|
||||||
|
- `state` (string, optional, default `"all"`) — conventional values `"open"`/`"closed"`/`"all"`, not
|
||||||
|
schema-enforced as an enum
|
||||||
|
- `labels` (array of strings, optional) — filter by label *name* (not ID)
|
||||||
|
- `since` (string, optional) — ISO 8601, issues updated after this time
|
||||||
|
- `before` (string, optional) — ISO 8601, issues updated before this time
|
||||||
|
- `page` (number, optional, default `1`)
|
||||||
|
- `per_page` (number, optional, default `30`)
|
||||||
|
|
||||||
|
**There is no `type` parameter and no `milestones` parameter**, despite both appearing in
|
||||||
|
`api-reference.md`. This tool cannot filter issues-vs-PRs or by milestone — see the Gotchas section
|
||||||
|
of SKILL.md for the consequence (PR entries can appear in results with no way to exclude them here).
|
||||||
|
|
||||||
|
**Call:**
|
||||||
|
```
|
||||||
|
list_issues owner: <owner> repo: <repo> state: "open"
|
||||||
|
```
|
||||||
|
|
||||||
|
**Response (list item):** `number`, `title`, `state`, `html_url`, `user`, `comments`, `created_at`,
|
||||||
|
`updated_at`, and optionally `labels` (`[]string`), `milestone` (`{id, title}`), `ref`, `deadline`.
|
||||||
|
Body and `closed_at` are omitted from list responses — call `issue_read method: "get"` for those.
|
||||||
|
|
||||||
|
Paginate with `page`/`per_page` until the returned count is less than `per_page`.
|
||||||
|
|
||||||
|
## `issue_read`
|
||||||
|
|
||||||
|
**Parameters (live schema, matches `api-reference.md`):**
|
||||||
|
- `method` (string, required, enum) — `"get"` | `"get_comments"` | `"get_labels"`
|
||||||
|
- `owner` (string, required)
|
||||||
|
- `repo` (string, required)
|
||||||
|
- `issue_number` (number, required)
|
||||||
|
|
||||||
|
**`get`** — full issue: `number`, `title`, `body`, `state`, `html_url`, `user`, `labels`
|
||||||
|
(`[]string`), `comments`, `created_at`, `updated_at`, `closed_at`, and optionally `assignees`
|
||||||
|
(`[]string`), `milestone` (`{id, title}`), `ref`, `deadline`, `is_pull` (present only when this
|
||||||
|
number is backed by a pull request — absent, not `false`, on true issues).
|
||||||
|
|
||||||
|
**`get_comments`** — array of `{id, body, user, html_url, created_at, updated_at}`.
|
||||||
|
|
||||||
|
**`get_labels`** — array of full label objects (`id`, `name`, `color`, `description` — not slimmed
|
||||||
|
to name strings, unlike the labels array on `get`).
|
||||||
|
|
||||||
|
**Call:**
|
||||||
|
```
|
||||||
|
issue_read method: "get" owner: <owner> repo: <repo> issue_number: <N>
|
||||||
|
```
|
||||||
|
|
||||||
|
Always check `is_pull` before treating a number as a plain issue — see the shared number-space
|
||||||
|
gotcha in SKILL.md.
|
||||||
|
|
||||||
|
## `issue_write`
|
||||||
|
|
||||||
|
**Parameters (live schema, matches `api-reference.md`):**
|
||||||
|
- `method` (string, required, enum) — `"create"` | `"update"` | `"add_comment"` | `"edit_comment"` |
|
||||||
|
`"add_labels"` | `"remove_label"` | `"replace_labels"` | `"clear_labels"`
|
||||||
|
- `owner` (string, required)
|
||||||
|
- `repo` (string, required)
|
||||||
|
- `issue_number` (number, required for every method except `"create"`)
|
||||||
|
- `title` (string, required for `"create"`)
|
||||||
|
- `body` (string, required for `"create"`, `"add_comment"`, `"edit_comment"`)
|
||||||
|
- `assignees` (array of strings, optional) — login names (see `references/enrichments.md` for why
|
||||||
|
this is usually omitted)
|
||||||
|
- `milestone` (number, optional) — milestone ID, never a title
|
||||||
|
- `state` (string, enum `"open"`/`"closed"`/`"all"`, optional) — for `"update"`
|
||||||
|
- `commentID` (number, optional, required for `"edit_comment"`)
|
||||||
|
- `labels` (array of numbers, optional) — label IDs, never names — for `add_labels`/`replace_labels`
|
||||||
|
- `label_id` (number, optional, required for `"remove_label"`) — singular, not the array form
|
||||||
|
- `ref` (string, optional) — branch association, informational only
|
||||||
|
- `deadline` (string, optional) — ISO 8601
|
||||||
|
- `remove_deadline` (boolean, optional)
|
||||||
|
|
||||||
|
**Create:**
|
||||||
|
```
|
||||||
|
issue_write method: "create"
|
||||||
|
owner: <owner> repo: <repo>
|
||||||
|
title: <title> body: <body>
|
||||||
|
labels: [<resolved IDs>] ← omit if none confidently inferred
|
||||||
|
milestone: <resolved ID> ← omit if none clearly fits
|
||||||
|
assignees: ["<login>"] ← omit if no default configured
|
||||||
|
```
|
||||||
|
|
||||||
|
**Close:**
|
||||||
|
```
|
||||||
|
issue_write method: "update" owner: <owner> repo: <repo> issue_number: <N> state: "closed"
|
||||||
|
```
|
||||||
|
There is no `method: "close"` — using one will error.
|
||||||
|
|
||||||
|
**Comment:**
|
||||||
|
```
|
||||||
|
issue_write method: "add_comment" owner: <owner> repo: <repo> issue_number: <N> body: <text>
|
||||||
|
```
|
||||||
|
|
||||||
|
**Apply resolved label IDs directly** (bypassing `references/enrichments.md`'s inference step, e.g.
|
||||||
|
when the caller already named exact labels):
|
||||||
|
```
|
||||||
|
issue_write method: "add_labels" owner: <owner> repo: <repo> issue_number: <N> labels: [<IDs>]
|
||||||
|
```
|
||||||
|
To replace all labels atomically instead of adding: `method: "replace_labels"`.
|
||||||
|
To remove one: `method: "remove_label" label_id: <single ID>`.
|
||||||
|
|
||||||
|
## Token scope
|
||||||
|
|
||||||
|
All of `list_issues`, `issue_read`, and `issue_write` are verified working under a token holding
|
||||||
|
`write:issue` + `write:repository`.
|
||||||
39
plugins/gitea/skills/gitea-issues/references/search.md
Normal file
39
plugins/gitea/skills/gitea-issues/references/search.md
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
---
|
||||||
|
topic: search
|
||||||
|
source_keys:
|
||||||
|
- gitea-mcp-repo
|
||||||
|
- gitea-mcp-slim-go
|
||||||
|
---
|
||||||
|
|
||||||
|
# `search_issues`
|
||||||
|
|
||||||
|
Call signature verified live against the deployed `gitea-mcp` server via `ToolSearch` at authoring
|
||||||
|
time (see `references/sources.md`) — confirmed to match `api-reference.md`.
|
||||||
|
|
||||||
|
**Parameters:**
|
||||||
|
- `query` (string, required) — the only hard-required parameter
|
||||||
|
- `state` (string, enum `"open"` | `"closed"` | `"all"`, optional)
|
||||||
|
- `type` (string, enum `"issues"` | `"pulls"`, optional) — **this tool has a working type filter**,
|
||||||
|
unlike `list_issues` (see `references/issues.md`)
|
||||||
|
- `labels` (string, optional) — comma-separated label **names** — a plain string, not the array form
|
||||||
|
`list_issues` uses
|
||||||
|
- `owner` (string, optional) — restrict results to one owner
|
||||||
|
- `page` (number, optional, default `1`)
|
||||||
|
- `per_page` (number, optional, default `30`)
|
||||||
|
|
||||||
|
**Call:**
|
||||||
|
```
|
||||||
|
search_issues query: <text>
|
||||||
|
```
|
||||||
|
|
||||||
|
**Narrowing the search:**
|
||||||
|
```
|
||||||
|
search_issues query: <text> owner: <owner> state: "open" type: "pulls" labels: "bug,urgent"
|
||||||
|
```
|
||||||
|
|
||||||
|
This is a cross-repository search (unlike `list_issues`, which is scoped to one `owner`/`repo`) —
|
||||||
|
useful when the caller doesn't know which repo an issue lives in, or wants results across an
|
||||||
|
organization. Pass `owner` to narrow scope if the caller does know it.
|
||||||
|
|
||||||
|
Paginate the same way as `list_issues`: iterate `page` until the returned count is less than
|
||||||
|
`per_page`.
|
||||||
41
plugins/gitea/skills/gitea-issues/references/sources.md
Normal file
41
plugins/gitea/skills/gitea-issues/references/sources.md
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
# Sources
|
||||||
|
|
||||||
|
**Note on call signatures:** per `docs/adr/0011-gitea-skill-deep-modules.md`, the tool parameter
|
||||||
|
signatures in `references/issues.md` and `references/search.md` were re-verified live via
|
||||||
|
`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).
|
||||||
|
|
||||||
|
## gitea-mcp-repo
|
||||||
|
|
||||||
|
- **URL:** https://gitea.com/gitea/gitea-mcp
|
||||||
|
- **Description:** Official gitea-mcp repository (v1.3.0); operation/*.go source files documenting all 55 MCP tools, their parameters, and CLI flags.
|
||||||
|
- **Research doc:** plugins/gitea/docs/research/docs/gitea/sources.md
|
||||||
|
- **Contributing files:** SKILL.md, references/issues.md, references/search.md, references/enrichments.md
|
||||||
|
- **Status:** `extracted`
|
||||||
|
|
||||||
|
## gitea-mcp-slim-go
|
||||||
|
|
||||||
|
- **URL:** https://gitea.com/gitea/gitea-mcp/raw/branch/main/operation/issue/slim.go
|
||||||
|
- **Description:** Slim response shape structs from gitea-mcp source; defines exactly which fields the MCP server returns for issues (label name-vs-ID slimming, milestone object-vs-string shape, `is_pull` presence on single-item reads only).
|
||||||
|
- **Research doc:** plugins/gitea/docs/research/docs/gitea/sources.md
|
||||||
|
- **Contributing files:** SKILL.md, references/issues.md
|
||||||
|
- **Status:** `extracted`
|
||||||
|
|
||||||
|
## context7-websites-gitea
|
||||||
|
|
||||||
|
- **URL:** context7:/websites/gitea
|
||||||
|
- **Description:** Official Gitea docs mirror on Context7 (docs.gitea.com content) — backs the automatic cross-reference rendering (`#N`/`!N`) that validates the "Depends on #N" dependency-linking convention.
|
||||||
|
- **Research doc:** plugins/gitea/docs/research/docs/gitea/sources.md
|
||||||
|
- **Contributing files:** references/enrichments.md
|
||||||
|
- **Status:** `extracted`
|
||||||
|
|
||||||
|
## context7-gitea-tea-cli
|
||||||
|
|
||||||
|
- **URL:** context7:/git_gitea_com/gitea_tea
|
||||||
|
- **Description:** Official `tea` CLI (reference Gitea client) docs on Context7 — practitioner command patterns for issues, PRs, and releases. Consulted alongside context7-websites-gitea while researching `workflow-conventions.md`'s cross-reference-linking section (both sources contribute to that research doc); its issue-specific command patterns did not end up informing any gitea-issues content beyond what context7-websites-gitea already backs.
|
||||||
|
- **Research doc:** plugins/gitea/docs/research/docs/gitea/sources.md
|
||||||
|
- **Contributing files:** (none)
|
||||||
|
- **Status:** `extracted`
|
||||||
25
plugins/gitea/skills/gitea-prs/README.md
Normal file
25
plugins/gitea/skills/gitea-prs/README.md
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
# gitea-prs
|
||||||
|
|
||||||
|
List, read, create, update, merge, and review Gitea pull requests.
|
||||||
|
|
||||||
|
## What it does
|
||||||
|
|
||||||
|
This skill handles the pull request lifecycle within the Gitea integration suite — listing and reading PRs (details, diff, changed files, CI status, reviews), creating and updating them (title, body, reviewers, labels, milestone), closing/reopening, merging with a chosen strategy and post-merge branch cleanup, and the full code-review flow (create a review with inline comments, submit it, dismiss or delete it). It composes `gitea-labels-milestones` for label/milestone ID resolution rather than duplicating that logic, and defers to `gitea-issues` for anything that turns out to be an issue rather than a PR (they share one number space) and to `gitea-branches`/`gitea-files` for the underlying branch/file operations behind a PR.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
```
|
||||||
|
/gitea-prs
|
||||||
|
```
|
||||||
|
|
||||||
|
Describe the PR or review task: list PRs, get a PR's status/diff/reviews, create or update a PR, merge one, or create/submit/dismiss a code review. The skill will determine owner/repo from context and resolve any label or milestone names via `gitea-labels-milestones` before writing them.
|
||||||
|
|
||||||
|
## Files
|
||||||
|
|
||||||
|
| File | Purpose |
|
||||||
|
|------|---------|
|
||||||
|
| `SKILL.md` | Skill instructions for agents — Gotchas, composition with `gitea-labels-milestones`, and the dispatch table |
|
||||||
|
| `references/pull-requests.md` | Execution detail for `list_pull_requests`, `pull_request_read` (get/get_diff/get_files/get_status), and `pull_request_write` (create/update/close/reopen/update_branch/add_reviewers/remove_reviewers) |
|
||||||
|
| `references/reviews.md` | Execution detail for `pull_request_review_write` (create/submit/delete/dismiss) and the review-related `pull_request_read` methods |
|
||||||
|
| `references/merging.md` | The merge workflow — CI vs. review/branch-protection gates, merge styles, branch cleanup, and the post-merge issue-close check |
|
||||||
|
| `references/sources.md` | Research sources backing the PR/review guidance |
|
||||||
68
plugins/gitea/skills/gitea-prs/SKILL.md
Normal file
68
plugins/gitea/skills/gitea-prs/SKILL.md
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
---
|
||||||
|
name: gitea-prs
|
||||||
|
|
||||||
|
description: >
|
||||||
|
Use when listing, reading, creating, updating, merging, or reviewing Gitea pull requests —
|
||||||
|
getting PR status/diff/changed files/CI status, opening a PR, updating title/body/reviewers,
|
||||||
|
closing/reopening, merging with a chosen strategy, or submitting/dismissing a code review with
|
||||||
|
inline comments. Composes `gitea-labels-milestones` to resolve label names or milestone titles
|
||||||
|
to the numeric IDs `pull_request_write` requires, rather than duplicating that resolution logic.
|
||||||
|
Do not use for issues (`gitea-issues`) or branch/commit operations (`gitea-branches`) — a number
|
||||||
|
the user mentions may refer to either an issue or a PR since they share one number space, so
|
||||||
|
confirm which domain applies before dispatching.
|
||||||
|
|
||||||
|
compatibility: Requires Gitea MCP server configured with write:issue and write:repository token scopes.
|
||||||
|
|
||||||
|
metadata:
|
||||||
|
category: integration
|
||||||
|
source_keys:
|
||||||
|
- gitea-mcp-repo
|
||||||
|
- gitea-mcp-slim-go
|
||||||
|
- context7-websites-gitea
|
||||||
|
- context7-gitea-tea-cli
|
||||||
|
version: "0.1.0"
|
||||||
|
|
||||||
|
allowed-tools: mcp__gitea__list_pull_requests mcp__gitea__pull_request_read mcp__gitea__pull_request_write mcp__gitea__pull_request_review_write
|
||||||
|
---
|
||||||
|
|
||||||
|
## Gotchas
|
||||||
|
|
||||||
|
- **Issues and PRs share one number space.** A number the user mentions (`#42`) might be an issue, not a PR — there is only one counter per repo. If you're not certain, call `pull_request_read method: "get"` and treat a 404 as "this number is an issue, not a PR" (or check `is_pull` on an `issue_read` response first if you already have one).
|
||||||
|
- **`pull_request_read method: "get"` returns `review_scomments`, not `review_comments`.** Source-level typo in gitea-mcp v1.3.0. Never reference `review_comments` — it will always be undefined.
|
||||||
|
- **`draft: true` on create prepends `"WIP:"` to the title.** There is no first-class draft field — Gitea implements draft PRs via title prefix. To un-draft, call `update` and pass the title without the `WIP:` prefix.
|
||||||
|
- **Cross-repo fork PRs require `head` as `"fork-owner:branch-name"`.** A bare branch name causes Gitea to search the base repo for it and return 422. Same-repo PRs use a bare branch name.
|
||||||
|
- **PR `milestone` is a bare title string, not `{id, title}`.** Unlike issues, you cannot recover a milestone's ID from a PR response. If you need the ID (e.g. to filter or to pass to another write), call into `gitea-labels-milestones` and match by title via `milestone_read method: "list"`.
|
||||||
|
- **CI status and review/approval state are independent merge gates.** `get_status` only reports CI. Branch-protection rules (required approvals, requested-reviewer coverage, stale-approval handling) are enforced server-side by the merge call itself and will error if unmet — passing CI does not mean the merge will succeed.
|
||||||
|
- **Reviews move through a state machine, not a single write.** `create` opens a review in `PENDING` state with inline comments attached; `submit` finalizes it with a terminal `state` (`APPROVED`/`REQUEST_CHANGES`/`COMMENT`). A submitted review can be `dismiss`ed afterward, but never deleted — `delete` only removes a review that was never submitted.
|
||||||
|
- **Merging a PR does not auto-close linked issues.** Unlike GitHub, Gitea has no merge-triggers-close event. It does parse closing keywords (`Fixes #N`, `Closes #N`) in commit messages landing on the default branch, so a non-squash merge that preserves those commit messages may auto-close the issue — but a squash merge rewrites history into one commit, so survival of the keyword depends on the squash commit's message. Always call `issue_read method: "get"` on any referenced issue after merging to check whether it already closed before deciding to close it explicitly.
|
||||||
|
|
||||||
|
## Composing `gitea-labels-milestones`
|
||||||
|
|
||||||
|
Before any `pull_request_write` call that includes a `labels` or `milestone` parameter, resolve names/titles to numeric IDs via `gitea-labels-milestones` — `label_read method: "list_repo_labels"` for label name → ID, `milestone_read method: "list"` for milestone title → ID. Never pass a label name string or milestone title string directly to `pull_request_write`; both parameters take numeric IDs only. This skill does not duplicate that lookup logic — it composes the shared skill.
|
||||||
|
|
||||||
|
## Dispatch
|
||||||
|
|
||||||
|
| Task | Tool | method |
|
||||||
|
|---|---|---|
|
||||||
|
| List PRs | `list_pull_requests` | — |
|
||||||
|
| Get PR details | `pull_request_read` | `"get"` |
|
||||||
|
| Get PR diff | `pull_request_read` | `"get_diff"` |
|
||||||
|
| Get PR changed files | `pull_request_read` | `"get_files"` |
|
||||||
|
| Get PR CI status | `pull_request_read` | `"get_status"` |
|
||||||
|
| Get PR reviews | `pull_request_read` | `"get_reviews"` |
|
||||||
|
| Get one review | `pull_request_read` | `"get_review"` |
|
||||||
|
| Get review inline comments | `pull_request_read` | `"get_review_comments"` |
|
||||||
|
| Create a PR | `pull_request_write` | `"create"` |
|
||||||
|
| Update a PR | `pull_request_write` | `"update"` |
|
||||||
|
| Close a PR | `pull_request_write` | `"close"` |
|
||||||
|
| Reopen a PR | `pull_request_write` | `"reopen"` |
|
||||||
|
| Merge a PR | `pull_request_write` | `"merge"` |
|
||||||
|
| Update branch from base | `pull_request_write` | `"update_branch"` |
|
||||||
|
| Add reviewers | `pull_request_write` | `"add_reviewers"` |
|
||||||
|
| Remove reviewers | `pull_request_write` | `"remove_reviewers"` |
|
||||||
|
| Create a review | `pull_request_review_write` | `"create"` |
|
||||||
|
| Submit a review | `pull_request_review_write` | `"submit"` |
|
||||||
|
| Delete a review | `pull_request_review_write` | `"delete"` |
|
||||||
|
| Dismiss a review | `pull_request_review_write` | `"dismiss"` |
|
||||||
|
|
||||||
|
For full parameter detail on listing/reading/creating/updating/closing PRs, read `references/pull-requests.md`. For review-specific detail (create/submit/delete/dismiss, inline comment shape), read `references/reviews.md`. For the merge workflow specifically (CI gate, merge styles, branch cleanup, post-merge issue check), read `references/merging.md`.
|
||||||
41
plugins/gitea/skills/gitea-prs/references/merging.md
Normal file
41
plugins/gitea/skills/gitea-prs/references/merging.md
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
---
|
||||||
|
topic: merging
|
||||||
|
source_keys:
|
||||||
|
- gitea-mcp-repo
|
||||||
|
- context7-websites-gitea
|
||||||
|
- context7-gitea-tea-cli
|
||||||
|
---
|
||||||
|
|
||||||
|
# Merge workflow
|
||||||
|
|
||||||
|
## Two independent gates
|
||||||
|
|
||||||
|
Before merging, two things can each independently block the merge, and only one of them is visible from `get_status`:
|
||||||
|
|
||||||
|
1. **CI status** — `pull_request_read method: "get_status"` returns the combined commit status for the PR's head commit. This reflects CI/build checks only.
|
||||||
|
2. **Review and branch-protection state** — required approval counts, an allowlist of required approvers/teams, whether requested reviewers have reviewed, and stale-approval handling (an approval given before new commits were pushed may be auto-dismissed or ignored, depending on repo settings). None of this is exposed via `get_status` — it is enforced server-side by the merge call itself, and repository admins are not exempt from it by default (an explicit "administrators must follow branch protection" setting is what removes that bypass).
|
||||||
|
|
||||||
|
A green `get_status` does not mean the merge will succeed. Treat both gates as independently checkable, and expect `pull_request_write method: "merge"` to return an error if branch-protection requirements aren't met even when CI is passing.
|
||||||
|
|
||||||
|
## `pull_request_write method: "merge"`
|
||||||
|
|
||||||
|
**Parameters** (in addition to `owner`, `repo`, `pull_number` — see `references/pull-requests.md` for the full parameter list):
|
||||||
|
- `merge_style` (string, optional, default `"merge"`) — `"merge"` | `"rebase"` | `"rebase-merge"` | `"squash"` | `"fast-forward-only"`
|
||||||
|
- `title` (string, optional) — override the merge/squash commit's title
|
||||||
|
- `message` (string, optional) — merge commit message (for squash, this becomes the squash commit's message — see the auto-close gotcha below)
|
||||||
|
- `delete_branch` (boolean, optional) — delete the head branch after a successful merge
|
||||||
|
- `force_merge` (boolean, optional) — merge even if checks are failing; use only when the user explicitly asks to override a failing CI status
|
||||||
|
- `merge_when_checks_succeed` (boolean, optional) — queue the merge to happen automatically once checks pass, instead of merging immediately
|
||||||
|
- `head_commit_id` (string, optional) — expected head SHA; supplying it lets the server detect if the branch moved since you last read it (conflict detection) rather than merging a stale diff
|
||||||
|
|
||||||
|
## Recommended sequence
|
||||||
|
|
||||||
|
1. Call `pull_request_read method: "get_status"` first. Report CI status to the user. Do not block the merge attempt solely because CI is failing unless the user asks you to stop — but do surface it before proceeding.
|
||||||
|
2. Call `pull_request_write method: "merge"` with the chosen `merge_style` (ask the user if unspecified; do not default to squash silently, since squash has the closing-keyword implication below) and `delete_branch: true` unless told otherwise.
|
||||||
|
3. If branch-protection requirements block the merge, the call itself will return the error — report it verbatim rather than retrying with `force_merge` unless the user explicitly asks to override.
|
||||||
|
|
||||||
|
## Merging does not auto-close linked issues
|
||||||
|
|
||||||
|
Gitea has no GitHub-style "merge triggers close" event. It does parse closing keywords (`Fixes #N`, `Closes #N`) in commit messages that land on the default branch — so a regular (non-squash) merge, which preserves each original commit message, can auto-close an issue this way if one of those commits used a closing keyword. A squash merge rewrites history into a single commit, so whether the keyword survives depends entirely on what `message` (or the default squash message) ends up being.
|
||||||
|
|
||||||
|
After any merge, call `issue_read method: "get"` (in `gitea-issues`) on any issue the PR references before deciding whether to close it explicitly. Closing an already-closed issue is a harmless no-op, but don't assume a manual close is always needed, and don't assume it never is.
|
||||||
75
plugins/gitea/skills/gitea-prs/references/pull-requests.md
Normal file
75
plugins/gitea/skills/gitea-prs/references/pull-requests.md
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
---
|
||||||
|
topic: pull-requests
|
||||||
|
source_keys:
|
||||||
|
- gitea-mcp-repo
|
||||||
|
- gitea-mcp-slim-go
|
||||||
|
---
|
||||||
|
|
||||||
|
# Pull request read/write execution detail
|
||||||
|
|
||||||
|
Parameter signatures below are cross-checked live against the deployed gitea-mcp server tool schemas at authoring time — not copied verbatim from the plugin's research doc for this domain, which has a known history of drifting from the deployed server (e.g. a prior `type` parameter that no longer exists on `list_issues`, and the `review_scomments` typo covered in `references/reviews.md`). Re-verify via `ToolSearch` before trusting this file if the gitea-mcp version changes.
|
||||||
|
|
||||||
|
## `list_pull_requests`
|
||||||
|
|
||||||
|
**Parameters:**
|
||||||
|
- `owner` (string, required)
|
||||||
|
- `repo` (string, required)
|
||||||
|
- `state` (string, optional, default `"all"`) — `"open"` | `"closed"` | `"all"`
|
||||||
|
- `sort` (string, optional, default `"recentupdate"`) — `"oldest"` | `"recentupdate"` | `"leastupdate"` | `"mostcomment"` | `"leastcomment"` | `"priority"`
|
||||||
|
- `milestone` (number, optional) — milestone ID filter, not a title
|
||||||
|
- `page` (number, optional, default 1)
|
||||||
|
- `per_page` (number, optional, default 30)
|
||||||
|
|
||||||
|
List responses trim PRs down to summary fields — `head`/`base` are bare ref strings and `milestone` does not appear as an object. Don't rely on this call to resolve a milestone's ID; see the Gotcha below.
|
||||||
|
|
||||||
|
## `pull_request_read`
|
||||||
|
|
||||||
|
**Parameters:**
|
||||||
|
- `method` (string, required) — `"get"` | `"get_diff"` | `"get_files"` | `"get_status"` | `"get_reviews"` | `"get_review"` | `"get_review_comments"`
|
||||||
|
- `owner` (string, required)
|
||||||
|
- `repo` (string, required)
|
||||||
|
- `pull_number` (number, required)
|
||||||
|
- `review_id` (number, optional) — required for `"get_review"` and `"get_review_comments"`; see `references/reviews.md`
|
||||||
|
- `binary` (boolean, optional) — include binary diff content for `"get_diff"`
|
||||||
|
- `page` (number, optional, default 1)
|
||||||
|
- `per_page` (number, optional, default 30)
|
||||||
|
|
||||||
|
`"get"`, `"get_diff"`, `"get_files"`, and `"get_status"` are covered here. `"get_reviews"`, `"get_review"`, and `"get_review_comments"` are covered in `references/reviews.md`.
|
||||||
|
|
||||||
|
- `"get"` returns the full PR object: state, draft, merged, mergeable flags; `head`/`base` as full objects (`{ref, sha, repo?}`); `milestone` as a bare title string (not `{id, title}`); `review_scomments` (typo, see `references/reviews.md`).
|
||||||
|
- `"get_diff"` returns raw diff text.
|
||||||
|
- `"get_files"` returns the list of changed file objects.
|
||||||
|
- `"get_status"` returns the combined commit status for the PR's head commit — CI result only, not review/approval state (see `references/merging.md`).
|
||||||
|
|
||||||
|
**Milestone gotcha:** because `pull_request_read` only ever returns a milestone title, never an ID, resolving "which milestone ID does this PR belong to" requires calling into `gitea-labels-milestones`' `milestone_read method: "list"` and matching by title. Do not attempt to infer or guess the ID.
|
||||||
|
|
||||||
|
## `pull_request_write`
|
||||||
|
|
||||||
|
**Parameters:**
|
||||||
|
- `method` (string, required) — `"create"` | `"update"` | `"close"` | `"reopen"` | `"merge"` | `"update_branch"` | `"add_reviewers"` | `"remove_reviewers"`
|
||||||
|
- `owner` (string, required)
|
||||||
|
- `repo` (string, required)
|
||||||
|
- `pull_number` (number, required for every method except `"create"` — this is enforced by convention, not by the tool's schema, so passing it incorrectly produces a runtime error rather than a client-side validation error)
|
||||||
|
- `title` (string, required for `"create"`; optional for `"update"`)
|
||||||
|
- `body` (string, required for `"create"`; optional for `"update"`)
|
||||||
|
- `head` (string, required for `"create"`) — source branch; same-repo PRs use a bare branch name, cross-repo fork PRs use `"fork-owner:branch-name"` (see Gotcha)
|
||||||
|
- `base` (string, required for `"create"`) — target branch
|
||||||
|
- `assignee` (string, optional) — single login
|
||||||
|
- `assignees` (array of strings, optional) — login names
|
||||||
|
- `milestone` (number, optional, for `"update"`) — milestone ID, never a title
|
||||||
|
- `state` (string, optional, for `"update"`) — `"open"` | `"closed"` (no `"all"` — unlike issue state filters)
|
||||||
|
- `allow_maintainer_edit` (boolean, optional, for `"update"`)
|
||||||
|
- `labels` (array of numbers, optional) — label IDs, never names — resolve via `gitea-labels-milestones` first
|
||||||
|
- `deadline` (string, optional) — ISO 8601
|
||||||
|
- `remove_deadline` (boolean, optional)
|
||||||
|
- `reviewers` (array of strings, optional, for `"add_reviewers"`/`"remove_reviewers"`) — login names
|
||||||
|
- `team_reviewers` (array of strings, optional, for `"add_reviewers"`/`"remove_reviewers"`)
|
||||||
|
- `draft` (boolean, optional, for `"create"`) — prepends `"WIP:"` to the title (see Gotcha)
|
||||||
|
|
||||||
|
Merge-specific parameters (`merge_style`, `delete_branch`, `force_merge`, `merge_when_checks_succeed`, `head_commit_id`, `message` as merge commit message) are covered in `references/merging.md`.
|
||||||
|
|
||||||
|
**Cross-repo head format:** `head` must be `"fork-owner:branch-name"` for a PR originating from a fork of the base repo. Passing a bare branch name causes Gitea to search for that branch in the base repo instead, and returns 422 when it isn't found there.
|
||||||
|
|
||||||
|
**Draft/WIP behavior:** `draft: true` on `"create"` is implemented by prepending `"WIP:"` to the title — there is no first-class draft boolean stored separately from the title. The title returned by subsequent reads will include the prefix. To un-draft, call `"update"` with `title` set to the same text minus the `"WIP:"` prefix; there is no dedicated undraft method.
|
||||||
|
|
||||||
|
**`update_branch`:** takes only `owner`, `repo`, `pull_number` — no other parameters. It merges the current base branch into the PR's head branch server-side, resolving a PR that Gitea reports as behind its base (analogous to GitHub's "Update branch" button). Use it when a PR shows `mergeable: false` or an out-of-date status due to base-branch drift rather than an actual conflict; if the head and base have truly diverged with conflicting changes, this call fails and the conflict must be resolved by pushing a merge/rebase to the head branch directly, outside this skill's scope.
|
||||||
43
plugins/gitea/skills/gitea-prs/references/reviews.md
Normal file
43
plugins/gitea/skills/gitea-prs/references/reviews.md
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
---
|
||||||
|
topic: reviews
|
||||||
|
source_keys:
|
||||||
|
- gitea-mcp-repo
|
||||||
|
- gitea-mcp-slim-go
|
||||||
|
---
|
||||||
|
|
||||||
|
# PR review execution detail
|
||||||
|
|
||||||
|
Parameter signatures below are cross-checked live against the deployed gitea-mcp server tool schema, not copied from the plugin's research doc verbatim — same sourcing discipline as `references/pull-requests.md`.
|
||||||
|
|
||||||
|
## Review state machine
|
||||||
|
|
||||||
|
A review is not a single write. It moves through states:
|
||||||
|
|
||||||
|
1. **`create`** — opens a review in `"PENDING"` state, optionally attaching inline comments. Nothing is visible to other users yet.
|
||||||
|
2. **`submit`** — finalizes the pending review with a terminal `state`: `"APPROVED"`, `"REQUEST_CHANGES"`, or `"COMMENT"`. This is the point at which the review becomes visible and counts toward merge-gate requirements (see `references/merging.md`).
|
||||||
|
3. **`dismiss`** — invalidates an already-submitted review (e.g. an approval that's no longer valid after force-push), with an optional `message` giving the reason. Dismissal does not delete the review record — it stays visible but marked dismissed.
|
||||||
|
4. **`delete`** — removes a review outright. Use only for a review that was never submitted (e.g. abandoning a `PENDING` draft); do not use `delete` to retract a submitted review — use `dismiss` instead.
|
||||||
|
|
||||||
|
## `pull_request_review_write`
|
||||||
|
|
||||||
|
**Parameters:**
|
||||||
|
- `method` (string, required) — `"create"` | `"submit"` | `"delete"` | `"dismiss"`
|
||||||
|
- `owner` (string, required)
|
||||||
|
- `repo` (string, required)
|
||||||
|
- `pull_number` (number, required)
|
||||||
|
- `review_id` (number, required for every method except `"create"`, which returns the ID to use for the follow-up `submit`/`delete`/`dismiss` call)
|
||||||
|
- `state` (string, optional) — `"APPROVED"` | `"REQUEST_CHANGES"` | `"COMMENT"` | `"PENDING"` — set on `"create"` (typically `"PENDING"`, or a terminal state to create-and-submit in one call if the server supports it) or `"submit"` (terminal state)
|
||||||
|
- `body` (string, optional) — overall review comment text
|
||||||
|
- `commit_id` (string, optional, for `"create"`) — anchors inline comments to a specific commit SHA (typically the PR's current head SHA from `pull_request_read method: "get"`)
|
||||||
|
- `message` (string, optional, for `"dismiss"`) — dismissal reason
|
||||||
|
- `comments` (array of objects, optional, for `"create"`) — inline comments, each: `{path, body, old_line_num, new_line_num}` — `path` is the file path, `body` is the comment text, `new_line_num` anchors to a line in the new (added) side of the diff, `old_line_num` anchors to a line in the old (removed) side; use whichever side the comment applies to, not both
|
||||||
|
|
||||||
|
## Reading reviews (`pull_request_read`)
|
||||||
|
|
||||||
|
- `method: "get_reviews"` — array of review summaries: `id`, `state`, `body`, `user` (login), `comments_count`, `submitted_at`, `html_url`, `stale` (bool — the PR was pushed to after this review was submitted, meaning it may be outdated), `official` (bool), `dismissed` (bool).
|
||||||
|
- `method: "get_review"` (requires `review_id`) — single review detail.
|
||||||
|
- `method: "get_review_comments"` (requires `review_id`) — array of inline comments: `id`, `body`, `path`, `position`, `old_position`, `diff_hunk`, `user`, `html_url`, `created_at`, `updated_at`.
|
||||||
|
|
||||||
|
**`review_scomments` typo:** the full PR object returned by `pull_request_read method: "get"` includes a field named `review_scomments` (a count), not `review_comments` — a source-level misspelling in gitea-mcp v1.3.0's `slim.go`. Do not write code or instructions that reference `review_comments` on that response; it will always be `undefined`. This is distinct from the `get_review_comments` method above, which is spelled correctly and returns the actual comment objects.
|
||||||
|
|
||||||
|
**Inline-comment field names differ between write and read.** The `comments` array on `pull_request_review_write method: "create"` uses `old_line_num`/`new_line_num`. The `get_review_comments` read response uses different field names for the same concept — `position` (new-side line) and `old_position` (old-side line). Do not assume the same key names apply on both sides of the round trip.
|
||||||
33
plugins/gitea/skills/gitea-prs/references/sources.md
Normal file
33
plugins/gitea/skills/gitea-prs/references/sources.md
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
# Sources
|
||||||
|
|
||||||
|
## gitea-mcp-repo
|
||||||
|
|
||||||
|
- **URL:** https://gitea.com/gitea/gitea-mcp
|
||||||
|
- **Description:** Official gitea-mcp repository (v1.3.0) — `operation/*.go` source files documenting all 55 MCP tools, their parameters, and CLI flags. Live tool schemas (`list_pull_requests`, `pull_request_read`, `pull_request_write`, `pull_request_review_write`) were verified directly against the deployed MCP server via `ToolSearch` at authoring time, per this repo's process for resolving schema-vs-docs drift, rather than copied from the derived research doc.
|
||||||
|
- **Research doc:** plugins/gitea/docs/research/docs/gitea/sources.md
|
||||||
|
- **Contributing files:** SKILL.md, references/pull-requests.md, references/reviews.md, references/merging.md
|
||||||
|
- **Status:** `extracted`
|
||||||
|
|
||||||
|
## gitea-mcp-slim-go
|
||||||
|
|
||||||
|
- **URL:** https://gitea.com/gitea/gitea-mcp/raw/branch/main/operation/pull/slim.go
|
||||||
|
- **Description:** Slim response shape structs from gitea-mcp source — defines exactly which fields the MCP server returns for PRs and reviews, including the `review_scomments` typo and the PR-response milestone-as-title-string quirk.
|
||||||
|
- **Research doc:** plugins/gitea/docs/research/docs/gitea/sources.md
|
||||||
|
- **Contributing files:** SKILL.md, references/pull-requests.md, references/reviews.md
|
||||||
|
- **Status:** `extracted`
|
||||||
|
|
||||||
|
## context7-websites-gitea
|
||||||
|
|
||||||
|
- **URL:** context7:/websites/gitea
|
||||||
|
- **Description:** Official Gitea docs mirror on Context7 — branch protection rules, PR review/merge gating behavior, and automatic issue/PR cross-reference linking. Backfills the external/best-practice gap left by the original docs.gitea.com fetch timeout.
|
||||||
|
- **Research doc:** plugins/gitea/docs/research/docs/gitea/sources.md
|
||||||
|
- **Contributing files:** SKILL.md, references/merging.md
|
||||||
|
- **Status:** `extracted`
|
||||||
|
|
||||||
|
## context7-gitea-tea-cli
|
||||||
|
|
||||||
|
- **URL:** context7:/git_gitea_com/gitea_tea
|
||||||
|
- **Description:** Official `tea` CLI (reference Gitea client) docs on Context7 — practitioner command patterns for PR review workflows.
|
||||||
|
- **Research doc:** plugins/gitea/docs/research/docs/gitea/sources.md
|
||||||
|
- **Contributing files:** references/merging.md
|
||||||
|
- **Status:** `extracted`
|
||||||
22
plugins/gitea/skills/gitea-workflow/README.md
Normal file
22
plugins/gitea/skills/gitea-workflow/README.md
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
# gitea-workflow
|
||||||
|
|
||||||
|
Human-facing entry point and router for the Gitea integration.
|
||||||
|
|
||||||
|
## What it does
|
||||||
|
|
||||||
|
This skill is the conversational front door to the Gitea suite — it replaces the old flat `/gitea` skill. On its own it never calls a Gitea MCP tool; it composes the six domain skills (`gitea-issues`, `gitea-labels-milestones`, `gitea-prs`, `gitea-branches`, `gitea-files`, `gitea-releases`). It handles the no-args status check-in (open issues + open PRs), resolves ambiguous issue-or-PR numbers before dispatching (issues and PRs share one number space), and points a user or agent to the right domain skill when it's unclear which one applies.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
```
|
||||||
|
/gitea-workflow
|
||||||
|
```
|
||||||
|
|
||||||
|
Invoke with no arguments for a status check-in, with a bare number to resolve and show issue or PR detail, or with a general request to be routed to the right domain skill.
|
||||||
|
|
||||||
|
## Files
|
||||||
|
|
||||||
|
| File | Purpose |
|
||||||
|
|------|---------|
|
||||||
|
| `SKILL.md` | Skill instructions for agents — Gotchas, status view, ambiguous-number resolution, and the domain-skill index |
|
||||||
|
| `references/sources.md` | Research sources backing the routing/status guidance |
|
||||||
74
plugins/gitea/skills/gitea-workflow/SKILL.md
Normal file
74
plugins/gitea/skills/gitea-workflow/SKILL.md
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
---
|
||||||
|
name: gitea-workflow
|
||||||
|
|
||||||
|
description: >
|
||||||
|
Use when a human wants a general or ambiguous Gitea status check or isn't sure which Gitea
|
||||||
|
domain skill applies — a no-args check-in ("what's going on in the repo", "any updates?"),
|
||||||
|
a bare-numbered reference that could be an issue or a PR ("what's the status of #42", "what's
|
||||||
|
happening with #17"), or a request to discover which Gitea capability handles a task. This is
|
||||||
|
the human-facing entry point and router for the Gitea integration — it replaces the old flat
|
||||||
|
`/gitea` invocation (now `/gitea-workflow`) and composes the six domain skills
|
||||||
|
(`gitea-issues`, `gitea-labels-milestones`, `gitea-prs`, `gitea-branches`, `gitea-files`,
|
||||||
|
`gitea-releases`) rather than calling any Gitea MCP tool directly. Do not use this skill when
|
||||||
|
the domain is already known and unambiguous — invoke the matching domain skill directly instead
|
||||||
|
(e.g. "create an issue" → `gitea-issues`, "merge PR #10" → `gitea-prs`, "cut a release" →
|
||||||
|
`gitea-releases`). Do not use for local git operations with no Gitea component (use
|
||||||
|
`git-workflow`).
|
||||||
|
|
||||||
|
compatibility: Requires Gitea MCP server configured with a token; delegates all calls to the six
|
||||||
|
domain skills, which in turn require write:issue and write:repository scopes at minimum.
|
||||||
|
|
||||||
|
metadata:
|
||||||
|
category: integration
|
||||||
|
version: "0.1.0"
|
||||||
|
source_keys:
|
||||||
|
- gitea-mcp-repo
|
||||||
|
- gitea-mcp-slim-go
|
||||||
|
- context7-websites-gitea
|
||||||
|
---
|
||||||
|
|
||||||
|
## Gotchas
|
||||||
|
|
||||||
|
- **This skill never calls a Gitea MCP tool itself.** Every read or write goes through one of the six domain skills. If a request needs a raw `mcp__gitea__*` call that no domain skill exposes, that's a gap in a domain skill, not something to patch here.
|
||||||
|
- **Issues and PRs share one number space** — a bare number like `#42` could be either. Never guess from context clues alone; resolve it with a real call (see Step 2) before dispatching.
|
||||||
|
- **A 404 on the resolution call doesn't necessarily mean the number doesn't exist.** Gitea hides permission errors as not-found (documented in `gitea-issues`' Gotchas). If resolution 404s unexpectedly, say so and suggest checking token scope rather than reporting "no such issue or PR."
|
||||||
|
|
||||||
|
## Step 1 — Default status view (no args)
|
||||||
|
|
||||||
|
When invoked with no specific request, give a status check-in:
|
||||||
|
|
||||||
|
1. Invoke `gitea-issues` to list open issues (`state: "open"`).
|
||||||
|
2. Invoke `gitea-prs` to list open PRs (`state: "open"`).
|
||||||
|
3. Run both in parallel — they're independent reads.
|
||||||
|
4. Report as two sections, "Open Issues" and "Open Pull Requests", each as a compact list (number, title). This preserves the original flat `/gitea` skill's default behavior.
|
||||||
|
|
||||||
|
## Step 2 — Resolve an ambiguous number
|
||||||
|
|
||||||
|
When the user references a bare number without saying "issue" or "PR" (e.g. "what's going on with #42"):
|
||||||
|
|
||||||
|
1. Invoke `gitea-issues` to run `issue_read method: "get"` on that number.
|
||||||
|
2. Check the response's `is_pull` field:
|
||||||
|
- `true` → it's a PR. Invoke `gitea-prs` for full PR detail (status, diff, reviews as appropriate to the request) and present that instead.
|
||||||
|
- `false` or absent → it's an issue. Present the issue detail already retrieved.
|
||||||
|
3. If the resolution call 404s, don't conclude the number doesn't exist — report the 404 and suggest verifying token scope (`write:issue`) per `gitea-issues`' Gotchas, since permission errors are hidden as not-found in Gitea.
|
||||||
|
|
||||||
|
Never dispatch to `gitea-issues` or `gitea-prs` based on guessing from phrasing alone ("that sounds like a bug" is not evidence) — always resolve first.
|
||||||
|
|
||||||
|
## Step 3 — Route explicit but domain-unclear requests
|
||||||
|
|
||||||
|
For requests that name a capability but not obviously which skill owns it, use this index:
|
||||||
|
|
||||||
|
| Skill | Covers |
|
||||||
|
|---|---|
|
||||||
|
| `gitea-issues` | List/read/create/update issues, comments, search across issues and PRs. Composes `gitea-labels-milestones` for label/milestone resolution. |
|
||||||
|
| `gitea-labels-milestones` | Label and milestone CRUD, label inference from conversation context, resolving names/titles to the numeric IDs writes require. Cross-cutting — used by both `gitea-issues` and `gitea-prs`. |
|
||||||
|
| `gitea-prs` | List/read/create/update/merge PRs, code reviews. Composes `gitea-labels-milestones` the same way `gitea-issues` does. |
|
||||||
|
| `gitea-branches` | Branch list/create/delete, plus commit history (list commits, get a single commit by SHA). |
|
||||||
|
| `gitea-files` | Read/write/delete individual files, list a directory, walk the full repo tree. |
|
||||||
|
| `gitea-releases` | Release and tag CRUD — draft/prerelease flags, release notes, semver tags. |
|
||||||
|
|
||||||
|
If a request clearly names one of these (e.g. "create a milestone" → `gitea-labels-milestones`, "read this file from the repo" → `gitea-files`), invoke that skill directly rather than routing through here. Use this table only when the user or an upstream agent is unsure which skill applies.
|
||||||
|
|
||||||
|
## Step 4 — Report
|
||||||
|
|
||||||
|
Present results in plain language. For the status view, two labeled sections. For a resolved ambiguous number, say which domain it turned out to be before showing detail ("That's a pull request:" / "That's an issue:"). For routing, name the skill and hand off — don't duplicate its output format, let it report.
|
||||||
33
plugins/gitea/skills/gitea-workflow/references/sources.md
Normal file
33
plugins/gitea/skills/gitea-workflow/references/sources.md
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
# Sources
|
||||||
|
|
||||||
|
## gitea-mcp-repo
|
||||||
|
|
||||||
|
- **URL:** https://gitea.com/gitea/gitea-mcp
|
||||||
|
- **Description:** Official gitea-mcp repository (v1.3.0) — `operation/*.go` source files documenting all 55 MCP tools. This skill's status view relies on `list_issues`/`list_pull_requests` semantics (via `gitea-issues`/`gitea-prs`), and its ambiguous-number resolution relies on `issue_read`'s `is_pull` field, both verified against this source at authoring time.
|
||||||
|
- **Research doc:** plugins/gitea/docs/research/docs/gitea/sources.md
|
||||||
|
- **Contributing files:** SKILL.md
|
||||||
|
- **Status:** `extracted`
|
||||||
|
|
||||||
|
## gitea-mcp-slim-go
|
||||||
|
|
||||||
|
- **URL:** https://gitea.com/gitea/gitea-mcp/raw/branch/main/operation/issue/slim.go
|
||||||
|
- **Description:** Slim response shape structs from gitea-mcp source — confirms `is_pull` is present on a single-item `issue_read` response, the field this skill's resolution step depends on to distinguish an issue from a PR sharing the same number.
|
||||||
|
- **Research doc:** plugins/gitea/docs/research/docs/gitea/sources.md
|
||||||
|
- **Contributing files:** SKILL.md
|
||||||
|
- **Status:** `extracted`
|
||||||
|
|
||||||
|
## context7-websites-gitea
|
||||||
|
|
||||||
|
- **URL:** context7:/websites/gitea
|
||||||
|
- **Description:** Official Gitea docs mirror on Context7 — confirms issues and pull requests share a single per-repository number sequence, and that Gitea returns 404 for permission failures rather than a distinct 403, both facts this skill's resolution and error-handling steps depend on.
|
||||||
|
- **Research doc:** plugins/gitea/docs/research/docs/gitea/sources.md
|
||||||
|
- **Contributing files:** SKILL.md
|
||||||
|
- **Status:** `extracted`
|
||||||
|
|
||||||
|
## context7-gitea-tea-cli
|
||||||
|
|
||||||
|
- **URL:** context7:/git_gitea_com/gitea_tea
|
||||||
|
- **Description:** Official `tea` CLI docs on Context7 — practitioner conventions for issues, PRs, and releases. Consulted as part of the shared research pass but its content is domain-specific (PR/release workflow patterns), out of scope for pure status/routing behavior — no content from it was used in this skill.
|
||||||
|
- **Research doc:** plugins/gitea/docs/research/docs/gitea/sources.md
|
||||||
|
- **Contributing files:** (none)
|
||||||
|
- **Status:** `extracted`
|
||||||
33
plugins/gitea/sources.md
Normal file
33
plugins/gitea/sources.md
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
# Sources
|
||||||
|
|
||||||
|
## gitea-mcp-repo
|
||||||
|
|
||||||
|
- **URL:** https://gitea.com/gitea/gitea-mcp
|
||||||
|
- **Research doc:** plugins/gitea/docs/research/docs/gitea/sources.md
|
||||||
|
- **Description:** Official gitea-mcp repository (v1.3.0); operation/*.go source files documenting all 55 MCP tools, their parameters, and CLI flags — informs the orchestrator's operation index and its `delete_release`/`delete_tag` id-vs-name and pagination-default hard rules.
|
||||||
|
- **Contributing files:** agents/gitea-orchestrate.md, agents/gitea-orchestrate.agent.md
|
||||||
|
- **Status:** `extracted`
|
||||||
|
|
||||||
|
## gitea-mcp-slim-go
|
||||||
|
|
||||||
|
- **URL:** https://gitea.com/gitea/gitea-mcp/raw/branch/main/operation/issue/slim.go, https://gitea.com/gitea/gitea-mcp/raw/branch/main/operation/pull/slim.go, https://gitea.com/gitea/gitea-mcp/raw/branch/main/operation/repo/slim.go
|
||||||
|
- **Research doc:** plugins/gitea/docs/research/docs/gitea/sources.md
|
||||||
|
- **Description:** Slim response shape structs from gitea-mcp source; defines the `is_pull` field the orchestrator's Number resolution routine checks to disambiguate issue vs. PR numbers.
|
||||||
|
- **Contributing files:** agents/gitea-orchestrate.md, agents/gitea-orchestrate.agent.md
|
||||||
|
- **Status:** `extracted`
|
||||||
|
|
||||||
|
## context7-websites-gitea
|
||||||
|
|
||||||
|
- **URL:** context7:/websites/gitea
|
||||||
|
- **Research doc:** plugins/gitea/docs/research/docs/gitea/sources.md
|
||||||
|
- **Description:** Official Gitea docs mirror on Context7 — informs the default-branch protection hard rule and permission-errors-as-404 behavior the orchestrator surfaces via `not_found_or_forbidden`.
|
||||||
|
- **Contributing files:** agents/gitea-orchestrate.md, agents/gitea-orchestrate.agent.md
|
||||||
|
- **Status:** `extracted`
|
||||||
|
|
||||||
|
## context7-gitea-tea-cli
|
||||||
|
|
||||||
|
- **URL:** context7:/git_gitea_com/gitea_tea
|
||||||
|
- **Research doc:** plugins/gitea/docs/research/docs/gitea/sources.md
|
||||||
|
- **Description:** Official `tea` CLI docs on Context7 — practitioner conventions for release/tag semver naming and merge strategy choices that inform the orchestrator's destructive-operation gating around `merge-pr` and `delete-release`/`delete-tag`.
|
||||||
|
- **Contributing files:** agents/gitea-orchestrate.md, agents/gitea-orchestrate.agent.md
|
||||||
|
- **Status:** `extracted`
|
||||||
@@ -16,6 +16,7 @@ mapfile -t TEST_FILES < <(
|
|||||||
find "$REPO_ROOT" -name "*.bats" \
|
find "$REPO_ROOT" -name "*.bats" \
|
||||||
-not -path "*/tests/bats/*" \
|
-not -path "*/tests/bats/*" \
|
||||||
-not -path "*/test_helper/*" \
|
-not -path "*/test_helper/*" \
|
||||||
|
-not -path "*/.claude/worktrees/*" \
|
||||||
| sort
|
| sort
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ run_bats
|
|||||||
mapfile -t SCRIPTS < <(
|
mapfile -t SCRIPTS < <(
|
||||||
find "$SEARCH_ROOT" -name "test-*.sh" \
|
find "$SEARCH_ROOT" -name "test-*.sh" \
|
||||||
-not -path "*/.git/*" \
|
-not -path "*/.git/*" \
|
||||||
|
-not -path "*/.claude/worktrees/*" \
|
||||||
| sort
|
| sort
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user