fix: support gh pr list state filter

This commit is contained in:
Codex
2026-05-22 18:00:10 +00:00
parent 05b77151b8
commit 210f4b9e73
4 changed files with 68 additions and 10 deletions
+19 -8
View File
@@ -53,6 +53,7 @@ type IssueListJsonField = typeof ISSUE_LIST_JSON_FIELDS[number];
type PrListJsonField = typeof PR_LIST_JSON_FIELDS[number];
type PrReadJsonField = typeof PR_READ_JSON_FIELDS[number];
type IssueListState = typeof ISSUE_LIST_STATES[number];
type PrListState = typeof ISSUE_LIST_STATES[number];
type BodyUpdateMode = typeof BODY_UPDATE_MODES[number];
type BoardMutationSection = typeof BOARD_MUTATION_SECTIONS[number];
type BoardGithubStatus = typeof BOARD_GITHUB_STATUSES[number];
@@ -317,6 +318,7 @@ interface GitHubOptions {
prListJsonFields?: PrListJsonField[];
prJsonFields?: PrReadJsonField[];
listState: IssueListState;
prListState: PrListState;
mode: BodyUpdateMode;
expectUpdatedAt?: string;
expectBodySha?: string;
@@ -573,6 +575,12 @@ function parseIssueListState(args: string[]): IssueListState {
throw new Error(`unsupported gh issue list --state ${raw}; supported states: ${ISSUE_LIST_STATES.join(",")}`);
}
function parsePrListState(args: string[]): PrListState {
const raw = optionValue(args, "--state") ?? "all";
if ((ISSUE_LIST_STATES as readonly string[]).includes(raw)) return raw as PrListState;
throw new Error(`unsupported gh pr list --state ${raw}; supported states: ${ISSUE_LIST_STATES.join(",")}`);
}
function parseBodyUpdateMode(args: string[]): BodyUpdateMode {
const raw = optionValue(args, "--mode") ?? "replace";
if ((BODY_UPDATE_MODES as readonly string[]).includes(raw)) return raw as BodyUpdateMode;
@@ -655,7 +663,8 @@ function parseOptions(args: string[]): GitHubOptions {
issueListJsonFields: top === "issue" && sub === "list" ? parseIssueListJsonFields(requestedJsonFields) : undefined,
prListJsonFields: top === "pr" && sub === "list" ? parsePrListJsonFields(requestedJsonFields) : undefined,
prJsonFields: top === "pr" && isPrReadCommand(sub) ? parsePrReadJsonFields(requestedJsonFields) : undefined,
listState: parseIssueListState(args),
listState: top === "issue" && (sub === "list" || sub === "board-row" && args[2] === "list") ? parseIssueListState(args) : "open",
prListState: top === "pr" && sub === "list" ? parsePrListState(args) : "all",
mode: parseBodyUpdateMode(args),
expectUpdatedAt: optionValue(args, "--expect-updated-at"),
expectBodySha: optionValue(args, "--expect-body-sha"),
@@ -4729,15 +4738,16 @@ async function authStatus(repo: string): Promise<GitHubCommandResult> {
};
}
async function prList(repo: string, token: string, limit: number, jsonFields: PrListJsonField[] | undefined): Promise<GitHubCommandResult> {
async function prList(repo: string, token: string, state: PrListState, limit: number, jsonFields: PrListJsonField[] | undefined): Promise<GitHubCommandResult> {
const { owner, name } = repoParts(repo);
const prs = await githubRequest<GitHubPullRequest[]>(token, "GET", `/repos/${owner}/${name}/pulls?state=all&per_page=${limit}`);
if (isGitHubError(prs)) return commandError("pr list", repo, prs);
const prs = await githubRequest<GitHubPullRequest[]>(token, "GET", `/repos/${owner}/${name}/pulls?state=${state}&per_page=${limit}`);
if (isGitHubError(prs)) return commandError("pr list", repo, prs, { state, limit });
const fields = jsonFields ?? PR_LIST_JSON_FIELDS.slice();
return {
ok: true,
command: "pr list",
repo,
state,
limit,
count: prs.length,
jsonFields: fields,
@@ -4793,7 +4803,7 @@ export function ghHelp(): unknown {
"bun scripts/cli.ts gh issue board-row upsert <issueNumber> [--repo owner/name] --board-issue 20 --section open|closed [--category text] --branch <branch> --tasks <task> --summary <text> --focus <text> --validation <text> --progress <text> [--status OPEN|CLOSED] [--dry-run] [--expect-updated-at ts|--expect-body-sha sha256]",
"bun scripts/cli.ts gh issue board-row move <issueNumber> [--repo owner/name] --board-issue 20 --to open|closed [--status OPEN|CLOSED] [--dry-run] [--expect-body-sha sha256]",
"bun scripts/cli.ts gh issue board-row delete <issueNumber> [--repo owner/name] --board-issue 20 [--dry-run] [--expect-body-sha sha256]",
"bun scripts/cli.ts gh pr list [--repo owner/name] [--limit N] [--json number,title,state,url,updatedAt,createdAt,author,head,base,draft]",
"bun scripts/cli.ts gh pr list [--repo owner/name] [--state open|closed|all] [--limit N] [--json number,title,state,url,updatedAt,createdAt,author,head,base,draft]",
"bun scripts/cli.ts gh pr read <number> [--repo owner/name] [--json body,title,state,head,base,draft,headRefName,baseRefName,mergeable,mergeStateStatus,statusCheckRollup]",
"bun scripts/cli.ts gh pr view <number> [--repo owner/name] [compatibility alias for pr read]",
"bun scripts/cli.ts gh pr create --title <title> --body-file <file>|--body <text> --base <branch> --head <branch> [--repo owner/name] [--draft] [--dry-run]",
@@ -4808,6 +4818,7 @@ export function ghHelp(): unknown {
"Issue and PR create/read/update/comment/close/reopen use GitHub REST and do not require the gh binary when GH_TOKEN or GITHUB_TOKEN is present.",
"Token values are never printed; auth status reports only token source and presence.",
"issue list defaults to --state open and bounded --limit 30; supported --json fields are number,title,state,url,updatedAt,createdAt,author,labels and unknown fields fail structurally.",
"PR list defaults to --state all for compatibility with earlier UniDesk CLI behavior; supported states are open, closed, and all.",
"issue read is the canonical read path; view remains a compatibility alias. Read supports legacy --json field selection such as --json body and still exposes .data.issue.body for compatibility; unsupported fields fail structurally.",
"issue create accepts repeatable --label values and comma-separated labels; dry-run prints the parsed labels and non-dry-run sends them in the GitHub REST create-issue payload.",
"--body-file is the recommended source for Markdown bodies so real newlines, backticks, and tables are read as file bytes instead of shell arguments.",
@@ -4850,9 +4861,9 @@ export async function runGhCommand(args: string[]): Promise<GitHubCommandResult
const command = [top, sub].filter((value): value is string => value !== undefined).join(" ") || "gh";
return validationError(command, options.repo, "--notify-claudeqq-brief-diff is only supported by gh issue edit 24");
}
if (optionWasProvided(args, "--state") && !(top === "issue" && (sub === "list" || sub === "board-row" && third === "list"))) {
if (optionWasProvided(args, "--state") && !(top === "issue" && (sub === "list" || sub === "board-row" && third === "list") || top === "pr" && sub === "list")) {
const command = [top, sub].filter((value): value is string => value !== undefined).join(" ") || "gh";
return validationError(command, options.repo, "--state is only supported by gh issue list and gh issue board-row list");
return validationError(command, options.repo, "--state is only supported by gh issue list, gh issue board-row list, and gh pr list");
}
if (optionWasProvided(args, "--json") && !(top === "issue" && (isIssueReadCommand(sub) || sub === "list"))) {
const command = [top, sub].filter((value): value is string => value !== undefined).join(" ") || "gh";
@@ -5057,7 +5068,7 @@ export async function runGhCommand(args: string[]): Promise<GitHubCommandResult
const { token, probe } = resolveToken(true);
const missing = authRequired(options.repo, `pr ${sub}`, probe);
if (missing !== null || token === null) return missing ?? authRequired(options.repo, `pr ${sub}`, { present: false, source: null, ghFallbackAttempted: true });
if (sub === "list") return prList(options.repo, token, options.limit, options.prListJsonFields);
if (sub === "list") return prList(options.repo, token, options.prListState, options.limit, options.prListJsonFields);
if (sub === "read") return prRead(options.repo, token, parseNumber(third, "pr read"), options.prJsonFields);
return prView(options.repo, token, parseNumber(third, "pr view"), options.prJsonFields);
}