From a414222610e35a383e4dd933b1236457f08f8c4f Mon Sep 17 00:00:00 2001 From: mathias Date: Sat, 16 May 2026 20:43:29 +0000 Subject: [PATCH] =?UTF-8?q?docs:=20update=20sprint=20to=20v0.2=20patch=20?= =?UTF-8?q?=E2=80=94=20fixes=20#12,=20#24,=20#25?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .context/PROJECT.md | 121 ++++++++++++++++++++++++++++---------------- 1 file changed, 76 insertions(+), 45 deletions(-) diff --git a/.context/PROJECT.md b/.context/PROJECT.md index 934bde5..64260d2 100644 --- a/.context/PROJECT.md +++ b/.context/PROJECT.md @@ -39,6 +39,7 @@ - Conventional commits: `feat:`, `fix:`, `chore:`, `docs:`, `refactor:` - Branch naming: `feat/short-description`, `fix/short-description` - PRs: one concern per PR, description explains *why* not *what* +- **Branch protection:** always work on a feature branch, open a PR, never push directly to main ### Security - No secrets in code, ever — use env vars or SOPS-encrypted files @@ -76,68 +77,98 @@ When acting as a coding agent on this project: 3. If unsure about a convention, check `DECISIONS.md` or ask 4. Never modify files outside the project root without explicit permission 5. When adding a dependency, explain why in the commit message -6. For client projects: never send code or context to cloud APIs — use local models via LiteLLM +6. Always work on a feature branch and open a PR — never push directly to main +7. For client projects: never send code or context to cloud APIs — use local models via LiteLLM -## Current sprint — gitea-mcp v0.2 (2026-05-14) +## Current sprint — gitea-mcp v0.2 patch (2026-05-14) ### Context -This sprint implements new MCP tools needed for `hyperguild new-project` — -the automated project creation flow triggered from claude.ai. See brain knowledge -nodes `adr-new-project-gitea-first-github-mirror` and `roadmap-github-ingestion-pipeline` -for full background. +The main v0.2 batch (repo_create, repo_update, repo_mirror_push, repo_delete, +repo_tree, repo_topics_update, file_read dir-fix, issue_get, release_create, +create_project_from_template) was implemented and pushed directly to main. -### Issues to implement (priority order) +This sprint fixes three remaining gaps found during code review on 2026-05-14. +These are blockers for `hyperguild new-project`. -**Batch 1 — blockers (do first, one PR: `feat/repo-crud`)** +### Issues to fix (all three in one PR: `fix/v02-patch`) -| Issue | Tool | Gitea API | -|-------|------|-----------| -| #13 | `repo_create` | POST /api/v1/user/repos or /api/v1/orgs/{org}/repos | -| #16 | `repo_mirror_push` (add/list/delete) | POST/GET/DELETE /api/v1/repos/{owner}/{repo}/push_mirrors | -| #12 | `repo_update` | PATCH /api/v1/repos/{owner}/{repo} | +#### #12 — repo_update: add `archived` and `template` fields +**File:** `internal/gitea/repos.go` → `UpdateRepoArgs` struct +**File:** `internal/tools/repo_update.go` → input schema + args struct -**Batch 2 — quality of life (second PR: `feat/repo-ux`)** +Add to `UpdateRepoArgs`: +```go +Archived *bool +Template *bool +``` -| Issue | Tool | Gitea API | -|-------|------|-----------| -| #15 | `file_read` dir-path fix | existing endpoint, detect array vs object response | -| #14 | `repo_tree` | GET /api/v1/repos/{owner}/{repo}/git/trees/{sha}?recursive=true | -| #18 | `repo_topics_update` | PUT /api/v1/repos/{owner}/{repo}/topics | +Add to tool input schema: +```json +"archived": { + "type": "boolean", + "description": "Mark repo as archived (read-only). Requires confirm=." +}, +"template": { + "type": "boolean", + "description": "Toggle template repo flag." +} +``` -**Batch 3 — can wait** +Add confirm-guard for `archived=true` (same pattern as `private=false`): +```go +if args.Archived != nil && *args.Archived { + if args.Confirm != args.Name { + return nil, fmt.Errorf("setting archived=true is irreversible: set confirm=%q to proceed", args.Name) + } +} +``` -| Issue | Tool | Note | -|-------|------|------| -| #11 | `repo_delete` | HIGH risk — needs `confirm` param == repo name | -| #17 | `release_create` | POST /api/v1/repos/{owner}/{repo}/releases | +New test cases to add in `repo_update_test.go`: +- `TestRepoUpdateTool_Archive` — happy path with confirm +- `TestRepoUpdateTool_ArchiveRequiresConfirm` — missing confirm returns error +- `TestRepoUpdateTool_SetTemplate` — no confirm needed -### How to add a tool (pattern) +#### #24 — create_project_from_template: make template selectable +**File:** `internal/tools/create_project_from_template.go` -Every tool = 4 files following `internal/tools/repo_get.go` exactly: +Add optional `template_name` param to input schema: +```json +"template_name": { + "type": "string", + "enum": ["template-go-web", "template-go-agent"], + "description": "Template repo to generate from. Defaults to template-go-web.", + "default": "template-go-web" +} +``` -1. `internal/gitea/.go` — API client method (use PostJSON/PatchJSON/DeleteJSON) -2. `internal/tools/repo_.go` — tool handler with Descriptor() + Call() -3. `internal/tools/repo__test.go` — table-driven tests with httptest.NewServer -4. Registration in main — find where `NewRepoGet` is registered, add new tool same place +The tool should use `args.TemplateName` if set, fall back to the hardcoded default. +Remove the hardcoded template name from `cmd/gitea-mcp/main.go` constructor call — +the tool resolves it internally. -Key rules: -- Always call `t.a.Check(args.Owner)` before any API call (allowlist guard) -- Use `textOK(result)` for success output -- For `repo_mirror_push`: NEVER log or return `remote_password` in any output -- For `repo_update` with `private: false` and `repo_delete`: require `confirm` param == repo name +New test case: `TestCreateProjectFromTemplate_AgentTemplate` -### Token permissions needed +#### #25 — pr_files_diff: fix same diff returned for all files +**File:** `internal/tools/pr_files_diff.go` -New tools require these additional Gitea token scopes: -- `write:repository` — repo_create, repo_update, repo_mirror_push, repo_topics_update, release_create -- `delete_repo` — repo_delete +There is a loop bug where all file entries in the response contain the same diff +(the first file's diff is reused for every subsequent file). Find the loop and +ensure each iteration reads and assigns the correct diff for its own file. -Check current token: `curl -H "Authorization: token $GITEA_TOKEN" https://gitea.d-ma.be/api/v1/user` -If scopes are missing, update token in Gitea settings before running tests. +Reproduce: call `pr_files_diff` on any PR with 3+ files, verify each file has +a distinct diff. ### Definition of done -- `task check` passes (all tools, all batches) -- Each new tool manually callable via `claude mcp call` -- PR #1 (batch 1) merged before starting batch 2 -- Issue #19 (mirror flow e2e test) verified manually after batch 1 is deployed +- [ ] `task check` passes +- [ ] `repo_update` accepts `archived` and `template` params +- [ ] `archived=true` requires `confirm=` +- [ ] `create_project_from_template` accepts `template_name` param, defaults to `template-go-web` +- [ ] `pr_files_diff` returns distinct diff per file +- [ ] All new test cases pass +- [ ] PR `fix/v02-patch` merged to main via PR (not direct push) + +### After this sprint + +Next: `hyperguild new-project` v1 implementation. +See brain node `adr-new-project-gitea-first-github-mirror` for the full flow spec. +Also: verify end-to-end mirror flow (issue #19) once `repo_mirror_push` is confirmed working.