A 401/403 was handled as one thing, so watchpr re-minted on every
rejection and reported "token expired" for a permission boundary or an
anonymous run that had no token to expire, sending the reader after the
wrong problem.
Classify a 401/403 as a rejected credential, a permission denial, or a
request that carried no token, and re-mint only the first.
Reject a re-minted empty token instead of replaying anonymously.
Report the classified cause from --once as well as from the watch loop.
Document watchpr's exit behaviour per cause.
Filing an issue as unkin-agent means hand-rolling a POST to the issues
API with a manually minted token, the exact credential handling agentpr
exists to encapsulate.
- add `issue create`, `issue comment` and `issue edit`, mirroring the pr
command group's flags, output and errors
- add CreateIssue/EditIssue to the Gitea client, sharing EditOptions with
EditPR
- build both comment commands from one constructor so pr and issue
comments cannot drift off Gitea's shared endpoint
- cover create, edit, a missing repo, an API error and missing flags
A merged or closed PR no longer authorises a delete on its own: HEAD must
be contained in the PR's head commit or in origin/<branch>, otherwise the
worktree goes and the branch stays. Branch deletion runs `git branch -d`
first and falls back to -D only for a proven branch.
Reword the cherry check to say patches reached the default branch's
history, print the verdict --keep-branches will actually perform, and warn
when a PR listing hits the pagination cap instead of reading it as "no PR".
Agents leave their managed worktrees behind, and `agentws rm` takes one path at
a time with no idea whether a branch's work is safely upstream, so clearing an
accumulation by hand risks destroying unmerged commits.
- classify every managed worktree: dirty, PR open, upstream, or unproven
- remove only what is safe; delete the local branch only when work is upstream
- prove "upstream" with merge-base and git cherry, so squash merges count
- match a PR by head.label, which survives the branch deletion a merge does
- dry run by default; --yes applies, --keep-branches spares every branch
- read the Gitea path from origin's URL rather than assuming the owner
- treat a mid-run 404 on a tracked PR as terminal
- cap consecutive transient poll failures at 20 per PR
- reset the failure count on a successful poll
- export IsNotFound for callers to classify the abort
Vault-minted Gitea tokens last ~1h, far less than a watch, and every poll
past expiry 401'd into a warning while watchpr looked healthy.
- retry a rejected request once with a freshly minted token
- abort the watch when the fresh token is rejected too
- poll anonymously when no token can be minted, mint only on a real 401/403
FetchState fetched the PR (merged=true) but then failed the whole state
fetch when CommitStatus 404'd for a head commit that no longer existed
(the branch was deleted after a squash/rebase merge). The merge signal was
discarded, so the watch loop treated every post-merge poll as a transient
error and never exited -- the 37-minute hang seen in production.
- Add a typed APIError carrying the HTTP status so callers can detect a 404
without parsing error strings.
- FetchState now tolerates a 404 from CommitStatus (commit gone => no CI
status) and returns the authoritative merged/closed PR state.
- Regression tests: FetchState survives a 404 status; the full watch loop,
driven through a real client, detects a merge whose head commit is gone
(both fail/hang before the fix).
golangci-lint v2 (errcheck) flagged three unchecked resp.Body.Close()
returns in gitea.go and vault.go. Wrap each deferred Close in a closure
discarding the return, the idiomatic form for a deferred Close whose
error is intentionally ignored.
agentpr manages PRs/comments/whoami as unkin-agent (Vault AppRole -> gitea creds
-> Gitea API), fixing tea's post-as-Ben default. watchpr polls PRs and alerts
only on merge/close, human comment, CI failure, or lost mergeability.
- cobra multi-binary layout mirroring node-lookup (cmd/ + internal/)
- Makefile (build, patch|minor|major, completions, rpm), nfpm RPM with both
binaries + bash/zsh/fish completions, woodpecker CI publishing to rpm-internal
- unit tests for parsing, meaningful-change detection, and the Vault+Gitea client