forked from lei.chen/myxce
feat(tooling): add cc-sdd to Gitea sync skill
Syncs Kiro specs to Gitea milestones + one issue per phase, and buglog.json entries to Gitea issues. Idempotent (safe to re-run). Validated against nexa/xce: admin-config-tool spec + 14 bugs synced.
This commit is contained in:
parent
18e7a0e9e1
commit
bf6a9b3405
2 changed files with 1073 additions and 0 deletions
198
.claude/skills/gitea-sync/SKILL.md
Normal file
198
.claude/skills/gitea-sync/SKILL.md
Normal file
|
|
@ -0,0 +1,198 @@
|
|||
---
|
||||
name: gitea-sync
|
||||
description: Sync cc-sdd specs and OpenWolf buglog to Gitea milestones/issues in nexa/xce
|
||||
argument-hint: [--dry-run] [--spec <name>] [--bugs] [--since <date>]
|
||||
triggers:
|
||||
- /gitea-sync
|
||||
- sync to gitea
|
||||
- gitea sync
|
||||
- synchronize specs to gitea
|
||||
---
|
||||
|
||||
# Gitea Sync Skill
|
||||
|
||||
Sync cc-sdd specs (`.kiro/specs/`) and OpenWolf buglog (`.wolf/buglog.json`) to
|
||||
Gitea issues in `nexa/xce`. Files are ground truth — Gitea is a read-only mirror.
|
||||
Sync state (issue numbers) is stored in source files for idempotency.
|
||||
|
||||
## Invocation
|
||||
|
||||
```
|
||||
/gitea-sync # sync all specs + all bugs
|
||||
/gitea-sync --spec admin-config-tool # sync one spec
|
||||
/gitea-sync --bugs --since 2026-07-18 # sync recent bugs only
|
||||
/gitea-sync --dry-run # preview without making changes
|
||||
```
|
||||
|
||||
## Procedure
|
||||
|
||||
### 0. Parse arguments
|
||||
|
||||
- `--dry-run`: only report what would change, don't call MCP write tools
|
||||
- `--spec <name>`: sync only one spec directory
|
||||
- `--bugs`: sync bugs only (skip specs)
|
||||
- `--since <YYYY-MM-DD>`: only sync bugs with `last_seen >=` this date
|
||||
|
||||
### 1. Ensure labels exist
|
||||
|
||||
These labels must exist in `nexa/xce`. Use `mcp__gitea__label_read` to list
|
||||
existing labels, then `mcp__gitea__label_write` with method `create_repo_label`
|
||||
for any missing ones:
|
||||
|
||||
| Name | Color | Description |
|
||||
|------|-------|-------------|
|
||||
| `phase:requirements` | `6C5CE7` | Spec requirements phase |
|
||||
| `phase:design` | `6C5CE7` | Spec design phase |
|
||||
| `phase:tasks` | `6C5CE7` | Spec tasks phase |
|
||||
| `phase:implementation` | `F39C12` | Spec implementation phase |
|
||||
| `phase:complete` | `27AE60` | Spec complete |
|
||||
| `spec` | `3498DB` | Spec-tracked issue |
|
||||
| `bug` | `E74C3C` | Bug-tracked issue |
|
||||
| `bug:fixed` | `27AE60` | Bug resolved |
|
||||
| `blocked` | `E74C3C` | Blocked on dependency |
|
||||
|
||||
### 2. Sync Specs
|
||||
|
||||
For each spec directory in `.kiro/specs/` (or just `--spec <name>`):
|
||||
|
||||
1. Read `spec.json`. If it has `gitea.milestone_id` and `gitea.issues` with
|
||||
all three keys (`requirements_design`, `implementation`, `validation`),
|
||||
skip creation — the spec is already synced. Check phase states and
|
||||
update issue open/closed state if needed (step 2d).
|
||||
|
||||
2. If not synced:
|
||||
a. **Create milestone**: Use `mcp__gitea__milestone_write` method `create`.
|
||||
Title = spec name. Description = one-line summary + phase + blockers.
|
||||
b. **Create three phase issues** under that milestone via
|
||||
`mcp__gitea__issue_write` method `create`:
|
||||
|
||||
| Key | Title | Labels | Initial State |
|
||||
|-----|-------|--------|---------------|
|
||||
| `requirements_design` | `[{spec}] Requirements & Design` | spec, phase:requirements, phase:design | closed if both approved, else open |
|
||||
| `implementation` | `[{spec}] Implementation` | spec, phase:implementation | open |
|
||||
| `validation` | `[{spec}] Validation & Closure` | spec, phase:complete | open |
|
||||
|
||||
Body format for each issue (build from spec files):
|
||||
|
||||
**Requirements & Design body**: Phase status, requirements summary table
|
||||
(extract `## Requirements Summary` from `requirements.md`), blockers list,
|
||||
link to spec files.
|
||||
|
||||
**Implementation body**: Tasks generated/ready status, task checklist
|
||||
(extract `- [ ]` / `- [x]` from `tasks.md` if it exists), blockers list.
|
||||
|
||||
**Validation body**: Acceptance gate checklist, deferred future-spec items.
|
||||
|
||||
c. **Write sync state** back to `spec.json`:
|
||||
```json
|
||||
"gitea": {
|
||||
"milestone_id": <id>,
|
||||
"issues": {
|
||||
"requirements_design": <number>,
|
||||
"implementation": <number>,
|
||||
"validation": <number>
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
d. **Phase state updates** (for already-synced specs): Check `spec.json`
|
||||
approvals. If requirements AND design are approved → close the
|
||||
requirements_design issue via `mcp__gitea__issue_write` method `update`
|
||||
with `state: "closed"`. If implementation approved → close
|
||||
implementation and validation issues. If all approved → close milestone
|
||||
via `mcp__gitea__milestone_write` method `update`.
|
||||
|
||||
### 3. Sync Bugs
|
||||
|
||||
Read `.wolf/buglog.json`. For each entry:
|
||||
|
||||
1. **Skip** if:
|
||||
- Entry has `gitea_issue` field (already synced) AND bug was already fixed
|
||||
when synced (no state change needed).
|
||||
- Filter: if `--since <date>` provided, skip entries with
|
||||
`last_seen < <date>`.
|
||||
|
||||
2. **Create issue** for entries without `gitea_issue`:
|
||||
Use `mcp__gitea__issue_write` method `create`.
|
||||
|
||||
**Title**: `[<bug-id>] <first sentence of error_message>` (max 120 chars)
|
||||
|
||||
**Body**:
|
||||
```
|
||||
## Error
|
||||
<error_message>
|
||||
|
||||
## Root Cause
|
||||
<root_cause>
|
||||
|
||||
## Fix
|
||||
<fix> (or "*Not yet fixed*" if empty)
|
||||
|
||||
## Affected Files
|
||||
- <file> (split on commas)
|
||||
|
||||
## Tags
|
||||
`tag1` `tag2` ...
|
||||
|
||||
## Related Bugs
|
||||
- <related>
|
||||
|
||||
---
|
||||
*Synced from `.wolf/buglog.json`*
|
||||
```
|
||||
|
||||
**Labels**: Start with `["bug"]`. If `fix` is populated, add `bug:fixed`.
|
||||
Map known tags to labels: `asan`/`ubsan` → create `bug:asan` label,
|
||||
`SEGV`/`double-free`/`UAF` → `bug:crash`, `race`/`toctou` → `bug:race`,
|
||||
`ha`/`raft`/`election`/`failover` → `bug:ha`, `data-loss` → `bug:data-loss`.
|
||||
|
||||
**State**: `"closed"` if `fix` is populated, `"open"` otherwise.
|
||||
|
||||
**Milestone**: None (bugs span specs).
|
||||
|
||||
3. **Close fixed bugs**: For entries WITH `gitea_issue` where `fix` is now
|
||||
populated (was empty before — we track by checking if the Gitea issue is
|
||||
still open). Use `mcp__gitea__issue_write` method `update` with
|
||||
`state: "closed"`.
|
||||
|
||||
4. **Write `gitea_issue`** back to the buglog entry: add
|
||||
`"gitea_issue": <issue_number>` to the entry in `.wolf/buglog.json`.
|
||||
Read the full file, modify the matching entry, write back with
|
||||
`json.dumps(data, indent=2)`.
|
||||
|
||||
### 4. Report
|
||||
|
||||
Print summary: "Specs: N synced, M skipped | Bugs: X created, Y closed, Z skipped"
|
||||
|
||||
## Important Rules
|
||||
|
||||
- **Files are ground truth**. Never read Gitea state to update local files.
|
||||
The gitea_issue/milestone_id fields in local files only store sync mappings.
|
||||
- **Idempotent**. Items with existing `gitea_issue` or `gitea` state are skipped
|
||||
unless their phase/fix state changed.
|
||||
- **Labels**: Check existing labels before creating. Use label IDs (not names)
|
||||
in issue create calls — fetch with `mcp__gitea__label_read` first.
|
||||
- **Rate limiting**: Batch issue creation — create issues sequentially
|
||||
(a few per turn) to stay within API limits.
|
||||
- **Buglog is large** (~13K lines). Always use `--since` filter for
|
||||
practical runs (e.g., `--since 2026-07-18`). Without `--since`, sync ALL bugs.
|
||||
- **Private repo**: `nexa/xce` is private. MCP auth must have access.
|
||||
|
||||
## Gitea MCP Tool Reference
|
||||
|
||||
| Action | Tool | Method |
|
||||
|--------|------|--------|
|
||||
| List labels | `mcp__gitea__label_read` | `list_repo_labels` |
|
||||
| Create label | `mcp__gitea__label_write` | `create_repo_label` |
|
||||
| List milestones | `mcp__gitea__milestone_read` | `list` |
|
||||
| Create milestone | `mcp__gitea__milestone_write` | `create` |
|
||||
| List issues | `mcp__gitea__issue_read` | `get` (single) or use list |
|
||||
| Create issue | `mcp__gitea__issue_write` | `create` |
|
||||
| Update issue | `mcp__gitea__issue_write` | `update` |
|
||||
|
||||
For listing issues by milestone, use `mcp__gitea__issue_read` with `method: "get"`
|
||||
and `state: "all"`. The Gitea MCP may have limited filtering — for bulk listing,
|
||||
check the milestone's open_issues/closed_issues counters.
|
||||
|
||||
Note: issue `state: "closed"` may not work on `create` — if the issue is created
|
||||
as `"open"`, immediately update it with `method: "update"` + `state: "closed"`.
|
||||
Loading…
Add table
Add a link
Reference in a new issue