feat(forge): search + milestone filters, and a page trailer that can't lie

`list` already built its query with `q: None, milestones: None` — both
fields were on the request it was sending. So full-text search over
title and body is a flag, not a new verb, and a text match is only
useful composed with the other filters anyway.

The trailer was the real defect. It fired on `count == limit`, but the
forge clamps page size to its own `api.MAX_RESPONSE_ITEMS`: ask for 400,
get a full 50, and `50 != 400` kept it silent — suppressing the warning
in precisely the case where the truncation is invisible. It now reports
the real total from `X-Total-Count`, which the response header struct
already parsed and the call site discarded. The requested limit is not
clamped client-side: that ceiling is the remote's configuration, not
ours.
This commit is contained in:
atlas 2026-08-05 18:26:34 +02:00 committed by mara
commit 8e690c0694
2 changed files with 135 additions and 17 deletions

View file

@ -67,6 +67,8 @@ hive-forge diff 42 # unified diff (lockfile hunks colla
hive-forge diff 42 --full # include unfiltered lockfile hunks
hive-forge list # open issues/PRs
hive-forge list --kind pr --state all --page 2 # page 2 of all PRs (walk --page 1,2,… with --limit as page size for a repo-wide sweep)
hive-forge list --search "trust bundle" --state all # full-text over title AND body — the duplicate check
hive-forge list --milestone 11 --state all # what's left in a milestone (name or id, repeatable)
hive-forge milestone # list milestones
hive-forge branches deployed/ # filter branches by pattern
hive-forge tree-sha main # git tree SHA for a ref
@ -282,3 +284,15 @@ to discover valid label names before triaging or to audit the label set.
PR number is parsed back out of the push output (the AGit push
itself has no label field), so they're silently skipped if that
parse fails — same fallback as the deferred multi-line body.
- `list --milestone <name>` takes a milestone **name or id**, is
repeatable, and the forge *discards* one it doesn't recognise. So a
typo returns the **unfiltered** list rather than an empty one — the
failure looks like "this milestone contains everything", not like an
error. Confirm the spelling with `hive-forge milestone`. (Same
silent-discard shape as unknown labels above.)
- `list --limit N` is a *request*: the forge clamps page size to its own
`api.MAX_RESPONSE_ITEMS` (50 by default), so `--limit 400` returns at
most 50 rows. The stderr trailer reports the real total from the
response's `X-Total-Count` (`… 50 of 187 shown … 137 more`), so trust
the trailer, not the row count, when deciding whether you've seen
everything.