Three tied items on the v02 patch sprint — one PR.
Issues closed
#25 fix(pr_files_diff) — every file entry was showing the last file's diff. splitUnifiedDiff stored bytes.Buffer.Bytes() in the map and Reset()ed the buffer; the map entries aliased the shared backing array. Fix copies into a fresh slice per file. New TestPRFilesDiffPerFileIsolation asserts each file's diff contains its own header and none of the others'; verified failing on the prior code.
#24 fix(create_project_from_template) — template name was hardcoded at startup. Adds an optional template_name input field that overrides the server-configured default per call. No enum on the schema — server-side tmpl.Template check is the gate, so future templates (go-ml, go-service, …) drop in without redeploys. Server-configured default preserved for backward compatibility.
#12 feat(repo_update) — new tool for PATCH /api/v1/repos/{owner}/{name} with optional archived/description/private/website/template pointer fields. Only set fields are sent on the wire; zero-field calls return ErrValidation before any network hop. private: false is allowed but flagged in the tool description. (The ntfy confirmation hook hinted in the issue is out of scope here — that's a separate cross-cutting feature.)
Verification
task check green: context sync ✓, golangci-lint 0 issues, all tests with -race, govulncheck no callable vulns.
Regression test for #25 verified failing on prior code, passing after fix.
Three logical commits + one chore commit for pre-existing context-adapter drift from the upstream pgvector default change.
## Why
Three tied items on the v02 patch sprint — one PR.
## Issues closed
- **#25 fix(pr_files_diff)** — every file entry was showing the last file's diff. `splitUnifiedDiff` stored `bytes.Buffer.Bytes()` in the map and `Reset()`ed the buffer; the map entries aliased the shared backing array. Fix copies into a fresh slice per file. New `TestPRFilesDiffPerFileIsolation` asserts each file's diff contains its own header and none of the others'; verified failing on the prior code.
- **#24 fix(create_project_from_template)** — template name was hardcoded at startup. Adds an optional `template_name` input field that overrides the server-configured default per call. No enum on the schema — server-side `tmpl.Template` check is the gate, so future templates (go-ml, go-service, …) drop in without redeploys. Server-configured default preserved for backward compatibility.
- **#12 feat(repo_update)** — new tool for `PATCH /api/v1/repos/{owner}/{name}` with optional `archived`/`description`/`private`/`website`/`template` pointer fields. Only set fields are sent on the wire; zero-field calls return `ErrValidation` before any network hop. `private: false` is allowed but flagged in the tool description. (The ntfy confirmation hook hinted in the issue is out of scope here — that's a separate cross-cutting feature.)
## Verification
- `task check` green: context sync ✓, golangci-lint 0 issues, all tests with `-race`, govulncheck no callable vulns.
- Regression test for #25 verified failing on prior code, passing after fix.
- Three logical commits + one chore commit for pre-existing context-adapter drift from the upstream pgvector default change.
## Followup (not in this PR)
- ntfy confirmation hook for destructive PATCHes (`private:false`, `archived:true` reversion, etc.) — cross-cutting tool middleware.
Derived adapters drifted from canonical root .context/AGENT.md after
the pgvector default change landed upstream. Pure regeneration via
scripts/context-sync.sh, no manual edits. Required to make task check
pass before the feature commits on this branch.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
splitUnifiedDiff used bytes.Buffer to accumulate each file's diff,
then stored buf.Bytes() into the result map and called buf.Reset()
to start the next file. bytes.Buffer.Bytes() returns the buffer's
internal backing slice; Reset() resets length to 0 but reuses the
same backing array. As a result, every map entry aliased the same
storage, so all files ended up showing the LAST file's diff content.
Fix: copy the bytes into a fresh slice before storing in the map.
Adds TestPRFilesDiffPerFileIsolation as a regression test that
asserts each file entry contains its OWN diff --git header and
none of the other files' headers. Verified failing on the prior
code, passing after the fix.
Closes#25
The template name was hardcoded into the binary at startup via
NewCreateProjectFromTemplate("mathias", "template-go-web"), so
generating from a different template (e.g. template-go-agent)
required a code change and restart. The constructor already
parameterised it correctly — the gap was at the tool's input
schema, which never exposed template_name to the caller.
Adds an optional template_name input field. When set, it overrides
the server-configured default for that call only; when omitted,
behavior is unchanged. Template owner stays server-configured —
only the repo name is per-call.
Server-side validation already verifies the resolved template
exists and is marked as a template repo, so no enum constraint
is added — keeps the door open for future templates (go-ml,
go-service, ...) without redeploys.
Adds TestCreateProjectTemplateNameOverride verifying the override
directs both the template lookup and the /generate POST.
Closes#24
Adds a repo_update tool exposing PATCH /api/v1/repos/{owner}/{name}
with optional pointer fields (archived, description, private,
website, template). Only fields set by the caller are sent on the
wire, so the server patches exactly what was asked for.
Originally needed to archive ingestion-svc cleanly instead of
leaving a README tombstone, and to flip template-go-{agent,web}
to template=true so create_project_from_template stops failing
the "is not marked as template" guard.
Wire-level enforcement of "at least one field" returns ErrValidation
before any network call, preventing no-op PATCHes.
private=false (making a repo public) is allowed but flagged in the
tool description with a "verify intent before calling" warning.
The earlier issue draft suggested an ntfy confirmation hook for
that path — out of scope for this PR; the warning string is the
minimum that fits inside the tool surface today.
Wires NewRepoUpdate into cmd/gitea-mcp/main.go alongside the rest
of the repo_* family.
Closes#12
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Why
Three tied items on the v02 patch sprint — one PR.
Issues closed
#25 fix(pr_files_diff) — every file entry was showing the last file's diff.
splitUnifiedDiffstoredbytes.Buffer.Bytes()in the map andReset()ed the buffer; the map entries aliased the shared backing array. Fix copies into a fresh slice per file. NewTestPRFilesDiffPerFileIsolationasserts each file's diff contains its own header and none of the others'; verified failing on the prior code.#24 fix(create_project_from_template) — template name was hardcoded at startup. Adds an optional
template_nameinput field that overrides the server-configured default per call. No enum on the schema — server-sidetmpl.Templatecheck is the gate, so future templates (go-ml, go-service, …) drop in without redeploys. Server-configured default preserved for backward compatibility.#12 feat(repo_update) — new tool for
PATCH /api/v1/repos/{owner}/{name}with optionalarchived/description/private/website/templatepointer fields. Only set fields are sent on the wire; zero-field calls returnErrValidationbefore any network hop.private: falseis allowed but flagged in the tool description. (The ntfy confirmation hook hinted in the issue is out of scope here — that's a separate cross-cutting feature.)Verification
task checkgreen: context sync ✓, golangci-lint 0 issues, all tests with-race, govulncheck no callable vulns.Followup (not in this PR)
private:false,archived:truereversion, etc.) — cross-cutting tool middleware.The template name was hardcoded into the binary at startup via NewCreateProjectFromTemplate("mathias", "template-go-web"), so generating from a different template (e.g. template-go-agent) required a code change and restart. The constructor already parameterised it correctly — the gap was at the tool's input schema, which never exposed template_name to the caller. Adds an optional template_name input field. When set, it overrides the server-configured default for that call only; when omitted, behavior is unchanged. Template owner stays server-configured — only the repo name is per-call. Server-side validation already verifies the resolved template exists and is marked as a template repo, so no enum constraint is added — keeps the door open for future templates (go-ml, go-service, ...) without redeploys. Adds TestCreateProjectTemplateNameOverride verifying the override directs both the template lookup and the /generate POST. Closes #24Adds a repo_update tool exposing PATCH /api/v1/repos/{owner}/{name} with optional pointer fields (archived, description, private, website, template). Only fields set by the caller are sent on the wire, so the server patches exactly what was asked for. Originally needed to archive ingestion-svc cleanly instead of leaving a README tombstone, and to flip template-go-{agent,web} to template=true so create_project_from_template stops failing the "is not marked as template" guard. Wire-level enforcement of "at least one field" returns ErrValidation before any network call, preventing no-op PATCHes. private=false (making a repo public) is allowed but flagged in the tool description with a "verify intent before calling" warning. The earlier issue draft suggested an ntfy confirmation hook for that path — out of scope for this PR; the warning string is the minimum that fits inside the tool surface today. Wires NewRepoUpdate into cmd/gitea-mcp/main.go alongside the rest of the repo_* family. Closes #124122e1f2aeto3cccbfb8cb