github-pr-search.ts 2.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364
  1. /// <reference path="../env.d.ts" />
  2. import { tool } from "@opencode-ai/plugin"
  3. async function githubFetch(endpoint: string, options: RequestInit = {}) {
  4. const response = await fetch(`https://api.github.com${endpoint}`, {
  5. ...options,
  6. headers: {
  7. Authorization: `Bearer ${process.env.GITHUB_TOKEN}`,
  8. Accept: "application/vnd.github+json",
  9. "Content-Type": "application/json",
  10. ...options.headers,
  11. },
  12. })
  13. if (!response.ok) {
  14. throw new Error(`GitHub API error: ${response.status} ${response.statusText}`)
  15. }
  16. return response.json()
  17. }
  18. interface PR {
  19. title: string
  20. html_url: string
  21. }
  22. export default tool({
  23. description: `Use this tool to search GitHub pull requests by title and description.
  24. This tool searches PRs in the anomalyco/opencode repository and returns LLM-friendly results including:
  25. - PR number and title
  26. - Author
  27. - State (open/closed/merged)
  28. - Labels
  29. - Description snippet
  30. Use the query parameter to search for keywords that might appear in PR titles or descriptions.`,
  31. args: {
  32. query: tool.schema.string().describe("Search query for PR titles and descriptions"),
  33. limit: tool.schema.number().describe("Maximum number of results to return").default(10),
  34. offset: tool.schema.number().describe("Number of results to skip for pagination").default(0),
  35. },
  36. async execute(args) {
  37. const owner = "anomalyco"
  38. const repo = "opencode"
  39. const page = Math.floor(args.offset / args.limit) + 1
  40. const searchQuery = encodeURIComponent(`${args.query} repo:${owner}/${repo} type:pr state:open`)
  41. const result = await githubFetch(
  42. `/search/issues?q=${searchQuery}&per_page=${args.limit}&page=${page}&sort=updated&order=desc`,
  43. )
  44. if (result.total_count === 0) {
  45. return `No PRs found matching "${args.query}"`
  46. }
  47. const prs = result.items as PR[]
  48. if (prs.length === 0) {
  49. return `No other PRs found matching "${args.query}"`
  50. }
  51. const formatted = prs.map((pr) => `${pr.title}\n${pr.html_url}`).join("\n\n")
  52. return `Found ${result.total_count} PRs (showing ${prs.length}):\n\n${formatted}`
  53. },
  54. })