()
| 721 | } |
| 722 | |
| 723 | async function getUserPrompt() { |
| 724 | const customPrompt = process.env["PROMPT"] |
| 725 | // For repo events and issues events, PROMPT is required since there's no comment to extract from |
| 726 | if (isRepoEvent || isIssuesEvent) { |
| 727 | if (!customPrompt) { |
| 728 | const eventType = isRepoEvent ? "scheduled and workflow_dispatch" : "issues" |
| 729 | throw new Error(`PROMPT input is required for ${eventType} events`) |
| 730 | } |
| 731 | return { userPrompt: customPrompt, promptFiles: [] } |
| 732 | } |
| 733 | |
| 734 | if (customPrompt) { |
| 735 | return { userPrompt: customPrompt, promptFiles: [] } |
| 736 | } |
| 737 | |
| 738 | const reviewContext = getReviewCommentContext() |
| 739 | const mentions = (process.env["MENTIONS"] || "/opencode,/oc") |
| 740 | .split(",") |
| 741 | .map((m) => m.trim().toLowerCase()) |
| 742 | .filter(Boolean) |
| 743 | let prompt = (() => { |
| 744 | if (!isCommentEvent) { |
| 745 | return "Review this pull request" |
| 746 | } |
| 747 | const body = (payload as IssueCommentEvent | PullRequestReviewCommentEvent).comment.body.trim() |
| 748 | const bodyLower = body.toLowerCase() |
| 749 | if (mentions.some((m) => bodyLower === m)) { |
| 750 | if (reviewContext) { |
| 751 | return `Review this code change and suggest improvements for the commented lines:\n\nFile: ${reviewContext.file}\nLines: ${reviewContext.line}\n\n${reviewContext.diffHunk}` |
| 752 | } |
| 753 | return "Summarize this thread" |
| 754 | } |
| 755 | if (mentions.some((m) => bodyLower.includes(m))) { |
| 756 | if (reviewContext) { |
| 757 | return `${body}\n\nContext: You are reviewing a comment on file "${reviewContext.file}" at line ${reviewContext.line}.\n\nDiff context:\n${reviewContext.diffHunk}` |
| 758 | } |
| 759 | return body |
| 760 | } |
| 761 | throw new Error(`Comments must mention ${mentions.map((m) => "`" + m + "`").join(" or ")}`) |
| 762 | })() |
| 763 | |
| 764 | // Handle images |
| 765 | const imgData: { |
| 766 | filename: string |
| 767 | mime: string |
| 768 | content: string |
| 769 | start: number |
| 770 | end: number |
| 771 | replacement: string |
| 772 | }[] = [] |
| 773 | |
| 774 | // Search for files |
| 775 | // ie. <img alt="Image" src="https://github.com/user-attachments/assets/xxxx" /> |
| 776 | // ie. [api.json](https://github.com/user-attachments/files/21433810/api.json) |
| 777 | // ie.  |
| 778 | const mdMatches = prompt.matchAll(/!?\[.*?\]\((https:\/\/github\.com\/user-attachments\/[^)]+)\)/gi) |
| 779 | const tagMatches = prompt.matchAll(/<img .*?src="(https:\/\/github\.com\/user-attachments\/[^"]+)" \/>/gi) |
| 780 | const matches = [...mdMatches, ...tagMatches].sort((a, b) => a.index - b.index) |
no test coverage detected