mirror of
https://github.com/anomalyco/opencode.git
synced 2026-08-06 09:10:47 -04:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1c7bab77cb | |||
| 2a75aadf02 | |||
| 7560913b7d | |||
| ba02738d34 |
@@ -17,8 +17,6 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
fetch-depth: 1
|
fetch-depth: 1
|
||||||
|
|
||||||
- uses: ./.github/actions/setup-bun
|
|
||||||
|
|
||||||
- name: Install opencode
|
- name: Install opencode
|
||||||
run: curl -fsSL https://opencode.ai/install | bash
|
run: curl -fsSL https://opencode.ai/install | bash
|
||||||
|
|
||||||
@@ -28,94 +26,44 @@ jobs:
|
|||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
OPENCODE_PERMISSION: |
|
OPENCODE_PERMISSION: |
|
||||||
{
|
{
|
||||||
"bash": {
|
"bash": "deny",
|
||||||
"*": "deny",
|
"webfetch": "deny",
|
||||||
"gh issue*": "allow"
|
"edit": "deny",
|
||||||
},
|
"write": "deny"
|
||||||
"webfetch": "deny"
|
|
||||||
}
|
}
|
||||||
|
ISSUE_NUMBER: ${{ github.event.issue.number }}
|
||||||
|
REPO: ${{ github.repository }}
|
||||||
run: |
|
run: |
|
||||||
opencode run -m opencode/claude-sonnet-4-6 "A new issue has been created:
|
ISSUE_TITLE=$(gh issue view "$ISSUE_NUMBER" --repo "$REPO" --json title --jq .title)
|
||||||
|
ISSUE_BODY=$(gh issue view "$ISSUE_NUMBER" --repo "$REPO" --json body --jq .body)
|
||||||
|
|
||||||
Issue number: ${{ github.event.issue.number }}
|
PROMPT=$(cat <<EOF
|
||||||
|
Check this new issue for compliance and duplicates:
|
||||||
|
|
||||||
Lookup this issue with gh issue view ${{ github.event.issue.number }}.
|
CURRENT_ISSUE_NUMBER: $ISSUE_NUMBER
|
||||||
|
|
||||||
You have TWO tasks. Perform both, then post a SINGLE comment (if needed).
|
Title: $ISSUE_TITLE
|
||||||
|
|
||||||
---
|
Description:
|
||||||
|
$ISSUE_BODY
|
||||||
|
EOF
|
||||||
|
)
|
||||||
|
|
||||||
TASK 1: CONTRIBUTING GUIDELINES COMPLIANCE CHECK
|
COMMENT=$(opencode run --agent duplicate-issue "$PROMPT")
|
||||||
|
|
||||||
Check whether the issue follows our contributing guidelines and issue templates.
|
if [ "$COMMENT" = "No action required" ]; then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
This project has three issue templates that every issue MUST use one of:
|
BODY="_The following comment was made by an LLM, it may be inaccurate:_
|
||||||
|
|
||||||
1. Bug Report - requires a Description field with real content
|
$COMMENT"
|
||||||
2. Feature Request - requires a verification checkbox and description, title should start with [FEATURE]:
|
|
||||||
3. Question - requires the Question field with real content
|
|
||||||
|
|
||||||
Additionally check:
|
gh issue comment "$ISSUE_NUMBER" --repo "$REPO" --body "$BODY"
|
||||||
- No AI-generated walls of text (long, AI-generated descriptions are not acceptable)
|
|
||||||
- The issue has real content, not just template placeholder text left unchanged
|
|
||||||
- Bug reports should include some context about how to reproduce
|
|
||||||
- Feature requests should explain the problem or need
|
|
||||||
- We want to push for having the user provide system description & information
|
|
||||||
|
|
||||||
Do NOT be nitpicky about optional fields. Only flag real problems like: no template used, required fields empty or placeholder text only, obviously AI-generated walls of text, or completely empty/nonsensical content.
|
if [[ "$COMMENT" == *"<!-- issue-compliance -->"* ]]; then
|
||||||
|
gh issue edit "$ISSUE_NUMBER" --repo "$REPO" --add-label needs:compliance
|
||||||
---
|
fi
|
||||||
|
|
||||||
TASK 2: DUPLICATE CHECK
|
|
||||||
|
|
||||||
Search through existing issues (excluding #${{ github.event.issue.number }}) to find potential duplicates.
|
|
||||||
Consider:
|
|
||||||
1. Similar titles or descriptions
|
|
||||||
2. Same error messages or symptoms
|
|
||||||
3. Related functionality or components
|
|
||||||
4. Similar feature requests
|
|
||||||
|
|
||||||
Additionally, if the issue mentions keybinds, keyboard shortcuts, or key bindings, note the pinned keybinds issue #4997.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
POSTING YOUR COMMENT:
|
|
||||||
|
|
||||||
Based on your findings, post a SINGLE comment on issue #${{ github.event.issue.number }}. Build the comment as follows:
|
|
||||||
|
|
||||||
If the issue is NOT compliant, start the comment with:
|
|
||||||
<!-- issue-compliance -->
|
|
||||||
Then explain what needs to be fixed and that they have 2 hours to edit the issue before it is automatically closed. Also add the label needs:compliance to the issue using: gh issue edit ${{ github.event.issue.number }} --add-label needs:compliance
|
|
||||||
|
|
||||||
If duplicates were found, include a section about potential duplicates with links.
|
|
||||||
|
|
||||||
If the issue mentions keybinds/keyboard shortcuts, include a note about #4997.
|
|
||||||
|
|
||||||
If the issue IS compliant AND no duplicates were found AND no keybind reference, do NOT comment at all.
|
|
||||||
|
|
||||||
Use this format for the comment:
|
|
||||||
|
|
||||||
[If not compliant:]
|
|
||||||
<!-- issue-compliance -->
|
|
||||||
This issue doesn't fully meet our [contributing guidelines](../blob/dev/CONTRIBUTING.md).
|
|
||||||
|
|
||||||
**What needs to be fixed:**
|
|
||||||
- [specific reasons]
|
|
||||||
|
|
||||||
Please edit this issue to address the above within **2 hours**, or it will be automatically closed.
|
|
||||||
|
|
||||||
[If duplicates found, add:]
|
|
||||||
---
|
|
||||||
This issue might be a duplicate of existing issues. Please check:
|
|
||||||
- #[issue_number]: [brief description of similarity]
|
|
||||||
|
|
||||||
[If keybind-related, add:]
|
|
||||||
For keybind-related issues, please also check our pinned keybinds documentation: #4997
|
|
||||||
|
|
||||||
[End with if not compliant:]
|
|
||||||
If you believe this was flagged incorrectly, please let a maintainer know.
|
|
||||||
|
|
||||||
Remember: post at most ONE comment combining all findings. If everything is fine, post nothing."
|
|
||||||
|
|
||||||
recheck-compliance:
|
recheck-compliance:
|
||||||
if: github.event.action == 'edited' && contains(github.event.issue.labels.*.name, 'needs:compliance')
|
if: github.event.action == 'edited' && contains(github.event.issue.labels.*.name, 'needs:compliance')
|
||||||
@@ -129,8 +77,6 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
fetch-depth: 1
|
fetch-depth: 1
|
||||||
|
|
||||||
- uses: ./.github/actions/setup-bun
|
|
||||||
|
|
||||||
- name: Install opencode
|
- name: Install opencode
|
||||||
run: curl -fsSL https://opencode.ai/install | bash
|
run: curl -fsSL https://opencode.ai/install | bash
|
||||||
|
|
||||||
@@ -140,38 +86,54 @@ jobs:
|
|||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
OPENCODE_PERMISSION: |
|
OPENCODE_PERMISSION: |
|
||||||
{
|
{
|
||||||
"bash": {
|
"bash": "deny",
|
||||||
"*": "deny",
|
"webfetch": "deny",
|
||||||
"gh issue*": "allow"
|
"edit": "deny",
|
||||||
},
|
"write": "deny"
|
||||||
"webfetch": "deny"
|
|
||||||
}
|
}
|
||||||
|
ISSUE_NUMBER: ${{ github.event.issue.number }}
|
||||||
|
REPO: ${{ github.repository }}
|
||||||
run: |
|
run: |
|
||||||
opencode run -m opencode/claude-sonnet-4-6 "Issue #${{ github.event.issue.number }} was previously flagged as non-compliant and has been edited.
|
ISSUE_TITLE=$(gh issue view "$ISSUE_NUMBER" --repo "$REPO" --json title --jq .title)
|
||||||
|
ISSUE_BODY=$(gh issue view "$ISSUE_NUMBER" --repo "$REPO" --json body --jq .body)
|
||||||
|
|
||||||
Lookup this issue with gh issue view ${{ github.event.issue.number }}.
|
PROMPT=$(cat <<EOF
|
||||||
|
Recheck this edited issue for compliance:
|
||||||
|
|
||||||
Re-check whether the issue now follows our contributing guidelines and issue templates.
|
MODE: recheck-compliance
|
||||||
|
CURRENT_ISSUE_NUMBER: $ISSUE_NUMBER
|
||||||
|
|
||||||
This project has three issue templates that every issue MUST use one of:
|
Title: $ISSUE_TITLE
|
||||||
|
|
||||||
1. Bug Report - requires a Description field with real content
|
Description:
|
||||||
2. Feature Request - requires a verification checkbox and description, title should start with [FEATURE]:
|
$ISSUE_BODY
|
||||||
3. Question - requires the Question field with real content
|
EOF
|
||||||
|
)
|
||||||
|
|
||||||
Additionally check:
|
COMMENT=$(opencode run --agent duplicate-issue "$PROMPT")
|
||||||
- No AI-generated walls of text (long, AI-generated descriptions are not acceptable)
|
|
||||||
- The issue has real content, not just template placeholder text left unchanged
|
|
||||||
- Bug reports should include some context about how to reproduce
|
|
||||||
- Feature requests should explain the problem or need
|
|
||||||
- We want to push for having the user provide system description & information
|
|
||||||
|
|
||||||
Do NOT be nitpicky about optional fields. Only flag real problems like: no template used, required fields empty or placeholder text only, obviously AI-generated walls of text, or completely empty/nonsensical content.
|
if [ "$COMMENT" = "No action required" ]; then
|
||||||
|
gh issue edit "$ISSUE_NUMBER" --repo "$REPO" --remove-label needs:compliance || true
|
||||||
|
|
||||||
If the issue is NOW compliant:
|
IDS=$(gh api "repos/$REPO/issues/$ISSUE_NUMBER/comments" --jq '.[] | select(.body | contains("<!-- issue-compliance -->")) | .id')
|
||||||
1. Remove the needs:compliance label: gh issue edit ${{ github.event.issue.number }} --remove-label needs:compliance
|
for id in $IDS; do
|
||||||
2. Find and delete the previous compliance comment (the one containing <!-- issue-compliance -->) using: gh api repos/${{ github.repository }}/issues/${{ github.event.issue.number }}/comments --jq '.[] | select(.body | contains(\"<!-- issue-compliance -->\")) | .id' then delete it with: gh api -X DELETE repos/${{ github.repository }}/issues/${{ github.event.issue.number }}/comments/{id}
|
gh api -X DELETE "repos/$REPO/issues/comments/$id"
|
||||||
3. Post a short comment thanking them for updating the issue.
|
done
|
||||||
|
|
||||||
If the issue is STILL not compliant:
|
gh issue comment "$ISSUE_NUMBER" --repo "$REPO" --body "Thanks for updating your issue. It now meets our contributing guidelines. :+1:"
|
||||||
Post a comment explaining what still needs to be fixed. Keep the needs:compliance label."
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
gh issue edit "$ISSUE_NUMBER" --repo "$REPO" --add-label needs:compliance
|
||||||
|
|
||||||
|
BODY="_The following comment was made by an LLM, it may be inaccurate:_
|
||||||
|
|
||||||
|
$COMMENT"
|
||||||
|
|
||||||
|
EXISTING=$(gh api "repos/$REPO/issues/$ISSUE_NUMBER/comments" --jq '[.[] | select(.body | contains("<!-- issue-compliance -->")) | .id] | last // empty')
|
||||||
|
if [ -n "$EXISTING" ]; then
|
||||||
|
gh api -X PATCH "repos/$REPO/issues/comments/$EXISTING" -f body="$BODY"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
gh issue comment "$ISSUE_NUMBER" --repo "$REPO" --body "$BODY"
|
||||||
|
|||||||
@@ -6,6 +6,18 @@ on:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
check-standards:
|
check-standards:
|
||||||
|
if: |
|
||||||
|
github.event.pull_request.user.login != 'actions-user' &&
|
||||||
|
github.event.pull_request.user.login != 'opencode' &&
|
||||||
|
github.event.pull_request.user.login != 'rekram1-node' &&
|
||||||
|
github.event.pull_request.user.login != 'thdxr' &&
|
||||||
|
github.event.pull_request.user.login != 'kommander' &&
|
||||||
|
github.event.pull_request.user.login != 'jayair' &&
|
||||||
|
github.event.pull_request.user.login != 'fwang' &&
|
||||||
|
github.event.pull_request.user.login != 'adamdotdevin' &&
|
||||||
|
github.event.pull_request.user.login != 'iamdavidhill' &&
|
||||||
|
github.event.pull_request.user.login != 'R44VC0RP' &&
|
||||||
|
github.event.pull_request.user.login != 'opencode-agent[bot]'
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
|
|||||||
@@ -0,0 +1,98 @@
|
|||||||
|
---
|
||||||
|
mode: primary
|
||||||
|
hidden: true
|
||||||
|
model: opencode/claude-haiku-4-5
|
||||||
|
color: "#E67E22"
|
||||||
|
tools:
|
||||||
|
"*": false
|
||||||
|
"github-issue-search": true
|
||||||
|
---
|
||||||
|
|
||||||
|
You are a duplicate issue detection agent. When an issue is opened, your job is to search for potentially duplicate or related open issues.
|
||||||
|
|
||||||
|
You have two jobs:
|
||||||
|
|
||||||
|
1. Check if the issue follows our issue templates/contributing requirements.
|
||||||
|
2. Check for potential duplicate issues.
|
||||||
|
|
||||||
|
Use the github-issue-search tool to find potentially related issues.
|
||||||
|
|
||||||
|
IMPORTANT: The input will contain a line `CURRENT_ISSUE_NUMBER: NNNN`. Never mark that issue as a duplicate of itself.
|
||||||
|
|
||||||
|
The input may also contain `MODE: recheck-compliance`.
|
||||||
|
|
||||||
|
- When MODE is `recheck-compliance`, ONLY run compliance checks. Do not run duplicate checks. Do not include duplicate or keybind sections.
|
||||||
|
- When MODE is missing, do the full opened-issue behavior (compliance + duplicates + keybind note).
|
||||||
|
|
||||||
|
## Compliance checks
|
||||||
|
|
||||||
|
This project has three issue templates:
|
||||||
|
|
||||||
|
1. Bug Report - needs a Description field with real content.
|
||||||
|
2. Feature Request - title should start with `[FEATURE]:` and include verification checkbox + meaningful description.
|
||||||
|
3. Question - needs a Question field with real content.
|
||||||
|
|
||||||
|
Also check:
|
||||||
|
|
||||||
|
- no AI-generated walls of text
|
||||||
|
- required sections are not placeholder-only / unchanged template text
|
||||||
|
- bug reports include some repro context
|
||||||
|
- feature requests explain the problem/need
|
||||||
|
- encourage system information where relevant
|
||||||
|
|
||||||
|
Do not be nitpicky about optional fields. Only flag real issues (missing template/required content, placeholder-only content, obviously AI-generated wall of text, empty/nonsensical issue).
|
||||||
|
|
||||||
|
## Duplicate checks
|
||||||
|
|
||||||
|
Search for duplicates by trying multiple keyword combinations from the issue title/body. Prioritize:
|
||||||
|
|
||||||
|
- similar title/description
|
||||||
|
- same error/symptoms
|
||||||
|
- same component/feature area
|
||||||
|
|
||||||
|
If the issue mentions keybinds, keyboard shortcuts, or key bindings, include a note to check pinned issue #4997.
|
||||||
|
|
||||||
|
## Output rules
|
||||||
|
|
||||||
|
If MODE is `recheck-compliance` and the issue is compliant, output exactly:
|
||||||
|
|
||||||
|
No action required
|
||||||
|
|
||||||
|
If MODE is missing and the issue is compliant AND no duplicates are found AND no keybind note is needed, output exactly:
|
||||||
|
|
||||||
|
No action required
|
||||||
|
|
||||||
|
Otherwise output exactly one markdown comment body with this structure:
|
||||||
|
|
||||||
|
- In `recheck-compliance` mode: include only the non-compliant section and ending note.
|
||||||
|
- In default mode: include sections as needed (non-compliant, duplicates, keybind).
|
||||||
|
|
||||||
|
- If non-compliant, start with:
|
||||||
|
|
||||||
|
<!-- issue-compliance -->
|
||||||
|
|
||||||
|
This issue doesn't fully meet our [contributing guidelines](../blob/dev/CONTRIBUTING.md).
|
||||||
|
|
||||||
|
**What needs to be fixed:**
|
||||||
|
|
||||||
|
- [specific reason]
|
||||||
|
|
||||||
|
Please edit this issue to address the above within **2 hours**, or it will be automatically closed.
|
||||||
|
|
||||||
|
- If duplicates were found, add:
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
This issue might be a duplicate of existing issues. Please check:
|
||||||
|
|
||||||
|
- #1234: [brief reason]
|
||||||
|
|
||||||
|
- If keybind-related, add:
|
||||||
|
|
||||||
|
For keybind-related issues, please also check our pinned keybinds documentation: #4997
|
||||||
|
|
||||||
|
- If non-compliant, end with:
|
||||||
|
|
||||||
|
If you believe this was flagged incorrectly, please let a maintainer know.
|
||||||
|
|
||||||
|
Keep output concise. Do not wrap output in code fences.
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
/// <reference path="../env.d.ts" />
|
||||||
|
import { tool } from "@opencode-ai/plugin"
|
||||||
|
import DESCRIPTION from "./github-issue-search.txt"
|
||||||
|
|
||||||
|
async function githubFetch(endpoint: string, options: RequestInit = {}) {
|
||||||
|
const response = await fetch(`https://api.github.com${endpoint}`, {
|
||||||
|
...options,
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${process.env.GITHUB_TOKEN}`,
|
||||||
|
Accept: "application/vnd.github+json",
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
...options.headers,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`GitHub API error: ${response.status} ${response.statusText}`)
|
||||||
|
}
|
||||||
|
return response.json()
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Issue {
|
||||||
|
title: string
|
||||||
|
html_url: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export default tool({
|
||||||
|
description: DESCRIPTION,
|
||||||
|
args: {
|
||||||
|
query: tool.schema.string().describe("Search query for issue titles and descriptions"),
|
||||||
|
limit: tool.schema.number().describe("Maximum number of results to return").default(10),
|
||||||
|
offset: tool.schema.number().describe("Number of results to skip for pagination").default(0),
|
||||||
|
},
|
||||||
|
async execute(args) {
|
||||||
|
const owner = "anomalyco"
|
||||||
|
const repo = "opencode"
|
||||||
|
|
||||||
|
const page = Math.floor(args.offset / args.limit) + 1
|
||||||
|
const searchQuery = encodeURIComponent(`${args.query} repo:${owner}/${repo} type:issue state:open`)
|
||||||
|
const result = await githubFetch(
|
||||||
|
`/search/issues?q=${searchQuery}&per_page=${args.limit}&page=${page}&sort=updated&order=desc`,
|
||||||
|
)
|
||||||
|
|
||||||
|
if (result.total_count === 0) {
|
||||||
|
return `No issues found matching "${args.query}"`
|
||||||
|
}
|
||||||
|
|
||||||
|
const issues = result.items as Issue[]
|
||||||
|
|
||||||
|
if (issues.length === 0) {
|
||||||
|
return `No other issues found matching "${args.query}"`
|
||||||
|
}
|
||||||
|
|
||||||
|
const formatted = issues.map((issue) => `${issue.title}\n${issue.html_url}`).join("\n\n")
|
||||||
|
|
||||||
|
return `Found ${result.total_count} issues (showing ${issues.length}):\n\n${formatted}`
|
||||||
|
},
|
||||||
|
})
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
Use this tool to search GitHub issues by title and description.
|
||||||
|
|
||||||
|
This tool searches issues in the sst/opencode repository and returns LLM-friendly results including:
|
||||||
|
- Issue number and title
|
||||||
|
- Author
|
||||||
|
- State (open/closed/merged)
|
||||||
|
- Labels
|
||||||
|
- Description snippet
|
||||||
|
|
||||||
|
Use the query parameter to search for keywords that might appear in issue titles or descriptions.
|
||||||
Reference in New Issue
Block a user