nisse-review: later reviews, replies, rounds, stop and review (M7.5)

Back on a PR it reviewed: a new head gets a later review of the commits
since (each one's diff, through the API) and of its earlier points; what
was said since gets replies, answered where it was said or skipped with a
reason. It signs off once and stays quiet while still happy. Past
tuning.review.max_rounds it sums up for the operator and goes quiet,
until a push or someone other than the PR's author joins in. An
operator's `stop` quiets it; `review` asks for a fresh review.

Reviews carry numbered markers and replies their point's key, so
recovery posts nothing twice.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01J5Utyfzw7gF7UhjRDEtjTk
This commit is contained in:
dongarandClaude Opus 5.5 committed 2026-10-17 07:06:06 +00:00
1 parent 7e73b8fb37
commit 37bbac7e72
14 files changed
+1268 -157

No files matched your search

+27
View File
@@ -520,6 +520,33 @@ class GiteaClient:
)
return int(data["id"])
def commits_between(self, repo: str, base: str, head: str) -> list[str]:
"""The commits from ``base`` to ``head`` ("sha subject"), oldest
first. After a force-push that drops ``base``, Gitea counts from the
two heads' merge base."""
data = self._request("GET", f"/repos/{repo}/compare/{base}...{head}") or {}
found: list[str] = []
for commit in data.get("commits") or []:
message = str((commit.get("commit") or {}).get("message") or "")
subject = message.splitlines()[0] if message.strip() else ""
found.append(f"{commit['sha']} {subject}".rstrip())
return found[::-1] # Gitea lists the newest first
def commit_diff(self, repo: str, sha: str) -> str:
"""One commit's diff. Through the API, so a token reads private
repositories (the web's compare diff doesn't take one)."""
return self._raw(f"/repos/{repo}/git/commits/{sha}.diff").decode(
errors="replace"
)
def react(self, repo: str, comment_id: int, content: str) -> None:
"""A reaction (``+1``, ``eyes``, ...) on a PR's or issue's comment."""
self._request(
"POST",
f"/repos/{repo}/issues/comments/{comment_id}/reactions",
json={"content": content},
)
def close(self) -> None:
self._http.close()