feat: add pr list (task 0008)
All checks were successful
CI / test (pull_request) Successful in 30s
CI / test (push) Successful in 31s

Implements `pr list` with the two policies later PR slices reuse:
client-side filtering with the filtered-set count line (ADR 0005) and
the official-first reviewDecision via parallel per-PR review fetches
(ADR 0006), extracted into src/review.ts.

API-supported flags map to their params (--state, --author→poster,
--label name→ID, --label-id, --sort, --limit, --fields); --assignee,
--base, --head, and --draft filter in-process after full pagination,
with the count line's total taken from the filtered set. --search is
refused with a redirect to `search prs`.

Adds a boolText field extractor and a shared parsePositiveInt helper,
the latter also adopted by issue list's --limit parsing.
This commit was merged in pull request #8.
This commit is contained in:
2026-07-12 19:23:29 -04:00
parent 7a41807a8a
commit 6333058b72
7 changed files with 964 additions and 20 deletions

View File

@@ -71,6 +71,27 @@ export function parseEnumFlag<T extends string>(
return value as T;
}
/**
* Parse a flag's value as a positive integer, rejecting a bare switch or a
* non-integer with a uniform `VALIDATION_ERROR`. `label` names the flag in the
* message (e.g. "--limit", "--label-id"). Shared by every flag that takes one.
*/
export function parsePositiveInt(
value: string | true,
label: string,
suggestions: string[] = [],
): number {
const parsed = Number(value);
if (value === true || !Number.isInteger(parsed) || parsed < 1) {
throw axiError(
`Invalid ${label} value: ${String(value)} (expected a positive integer)`,
"VALIDATION_ERROR",
suggestions,
);
}
return parsed;
}
/** Split "--flag=value" into name and inline value; "--flag" has none. */
export function splitFlag(arg: string): SplitFlag {
const equals = arg.indexOf("=");