feat: support gh issue search

This commit is contained in:
Codex
2026-06-01 13:40:56 +00:00
parent 48f3f728e7
commit 2346c620b7
3 changed files with 55 additions and 15 deletions
@@ -525,6 +525,10 @@ async function startMockGitHub(): Promise<{ baseUrl: string; requests: MockReque
sendJson(res, 200, issueList.slice(0, 2));
return;
}
if (req.method === "GET" && req.url === "/search/issues?q=AgentRun+final+response+repo%3ApikasTech%2Funidesk+type%3Aissue&per_page=4") {
sendJson(res, 200, { total_count: 1, incomplete_results: false, items: issueList.slice(0, 1) });
return;
}
if (req.method === "GET" && req.url === "/repos/pikasTech/unidesk/issues?state=open&per_page=5") {
sendJson(res, 200, issueList);
return;
@@ -656,6 +660,7 @@ export async function runGhCliIssueGuardContract(): Promise<JsonRecord> {
assertCondition(usage.some((line) => line.includes("gh issue board-row upsert")), "gh help should list board-row upsert", { usage });
assertCondition(usage.some((line) => line.includes("gh issue board-row move")), "gh help should list board-row move", { usage });
assertCondition(usage.some((line) => line.includes("gh issue board-row delete")), "gh help should list board-row delete", { usage });
assertCondition(usage.some((line) => line.includes("gh issue list") && line.includes("--search text")), "gh help should list issue list search", { usage });
assertCondition(notes.some((line) => line.includes("canonical read path")), "gh help should state issue read is canonical", { notes });
assertCondition(notes.some((line) => line.includes("compatibility alias")), "gh help should state issue view is alias", { notes });
assertCondition(notes.some((line) => line.includes("owner/repo#number shorthand")), "gh help should explain read/view shorthand", { notes });
@@ -696,6 +701,12 @@ export async function runGhCliIssueGuardContract(): Promise<JsonRecord> {
assertCondition(listDefaultStateData.state === "open", "issue list should keep default state=open", listDefaultStateData);
assertCondition(mock.requests.some((request) => request.method === "GET" && request.url === "/repos/pikasTech/unidesk/issues?state=open&per_page=2"), "issue list default should query state=open", mock.requests);
const searchList = await runCli(["gh", "issue", "list", "--repo", "pikasTech/unidesk", "--state", "all", "--limit", "4", "--search", "AgentRun final response", "--json", "number,title,state,url"], env);
assertCondition(searchList.status === 0, "issue list should support search query", searchList.json ?? { stdout: searchList.stdout });
const searchListData = dataOf(searchList.json ?? {});
assertCondition(searchListData.search === "AgentRun final response", "issue list should expose search query", searchListData);
assertCondition(mock.requests.some((request) => request.method === "GET" && request.url === "/search/issues?q=AgentRun+final+response+repo%3ApikasTech%2Funidesk+type%3Aissue&per_page=4"), "issue list search should use GitHub Search Issues API with repo/type qualifiers", mock.requests);
const positionalRepoList = await runCli(["gh", "issue", "list", "pikasTech/HWLAB", "--state", "open", "--limit", "2", "--json", "number,title,state,url"], env);
assertCondition(positionalRepoList.status === 0, "issue list positional owner/repo should succeed", positionalRepoList.json ?? { stdout: positionalRepoList.stdout });
const positionalRepoListData = dataOf(positionalRepoList.json ?? {});