diff --git a/.github/workflows/opencode-pr.yml b/.github/workflows/opencode-pr.yml index fa63f65..ad4d289 100644 --- a/.github/workflows/opencode-pr.yml +++ b/.github/workflows/opencode-pr.yml @@ -12,9 +12,7 @@ # triggers: [pull_request] # variants: # - name: standard -# description: Uses standard GitHub Actions with direct API calls -# - name: nix -# description: Uses Nix for reproducible environment +# description: Uses OpenCode GitHub Action # --- name: OpenCode AI PR Review @@ -24,102 +22,119 @@ on: types: [opened, synchronize, reopened, ready_for_review] jobs: - review: + opencode: + # Don't run on draft PRs; do run when they become ready_for_review. + if: ${{ github.event.pull_request.draft == false }} runs-on: ubuntu-latest - if: github.event.pull_request.draft == false - + timeout-minutes: 10 + permissions: + id-token: write + contents: write + pull-requests: write + issues: read + steps: - - name: Checkout code + - name: Checkout repository uses: actions/checkout@v4 with: fetch-depth: 0 - - name: Get PR diff - id: diff + - name: Configure git run: | - git diff origin/${{ github.base_ref }}...HEAD > pr_diff.txt - echo "diff_path=pr_diff.txt" >> $GITHUB_OUTPUT + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" - - name: Get previous review comments - id: previous-comments - uses: actions/github-script@v7 - with: - script: | - const comments = await github.rest.issues.listComments({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: context.issue.number - }); - const opencodeComments = comments.data.filter(c => - c.user.login === 'github-actions[bot]' && - c.body.includes('OpenCode AI Review') - ); - return opencodeComments.map(c => c.body).join('\n---\n'); - - - name: Run OpenCode AI Review + - name: Run opencode + uses: anomalyco/opencode/github@latest env: KIMI_API_KEY: ${{ secrets.KIMI_API_KEY }} - PR_DIFF: ${{ steps.diff.outputs.diff_path }} - PREVIOUS_COMMENTS: ${{ steps.previous-comments.outputs.result }} - PR_TITLE: ${{ github.event.pull_request.title }} - PR_DESCRIPTION: ${{ github.event.pull_request.body }} - run: | - # Read the diff file - DIFF_CONTENT=$(cat "$PR_DIFF") - - # Create the review prompt - PROMPT=$(cat < review_response.json - - # Extract and post review - REVIEW_TEXT=$(cat review_response.json | jq -r '.choices[0].message.content') - - echo "$REVIEW_TEXT" > review_output.txt - cat review_output.txt - - - name: Post review comment - uses: actions/github-script@v7 with: - script: | - const fs = require('fs'); - const reviewText = fs.readFileSync('review_output.txt', 'utf8'); - const formattedReview = `## OpenCode AI Review 🤖\n\n${reviewText}`; + model: kimi-for-coding/k2p5 + prompt: | + You are reviewing a pull request. Analyze the code changes and output your review in the following STRICT STRUCTURE: + + --- + + ## 📋 Summary + First, check if the PR description mentions any linked issues (e.g., "Closes #123", "Fixes #456", "Resolves #789"). + + If linked issues are found: + - Mention the issue number(s) explicitly + - Verify the PR actually implements what the issue(s) requested + - State whether the implementation fully satisfies the issue requirements + + Then provide 2-3 sentences summarizing the PR purpose, scope, and overall quality. + + ## 🔴 Critical Issues (Must Fix - Blocks Merge) + Only issues that could cause crashes, security vulnerabilities, data loss, or major bugs. + + For each issue, use this exact format: + ``` + **[CRITICAL]** `File:Line` - Issue Title + **Confidence:** High|Medium|Low (how sure you are this is a real problem) + **Description:** Clear explanation of the issue + **Impact:** What could go wrong if merged + **Suggested Fix:** Specific code changes needed + ``` + + ## âš ī¸ High Priority Issues (Should Fix) + Significant code quality issues, potential bugs, or architectural problems. + + Same format as Critical, but with **[HIGH]** prefix. + + ## 💡 Medium Priority Issues (Nice to Fix) + Style issues, minor optimizations, or code clarity improvements. - await github.rest.issues.createComment({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: context.issue.number, - body: formattedReview - }); + Same format, with **[MEDIUM]** prefix. + + ## â„šī¸ Low Priority Suggestions (Optional) + Minor suggestions, documentation improvements, or subjective preferences. + + Same format, with **[LOW]** prefix. + + ## 📊 SOLID Principles Score + | Principle | Score | Notes | + |-----------|-------|-------| + | Single Responsibility | 0-10 | Brief justification | + | Open/Closed | 0-10 | Brief justification | + | Liskov Substitution | 0-10 | Brief justification | + | Interface Segregation | 0-10 | Brief justification | + | Dependency Inversion | 0-10 | Brief justification | + | **Average** | **X.X** | | + + ## đŸŽ¯ Final Assessment + + ### Overall Confidence Score: XX% + Rate your confidence in this PR being ready to merge (0-100%). + **How to interpret:** + - 0-30%: Major concerns, do not merge without significant rework + - 31-60%: Moderate concerns, several issues need addressing + - 61-80%: Minor concerns, mostly ready with some fixes + - 81-100%: High confidence, ready to merge or with trivial fixes + + ### Confidence Breakdown: + - **Code Quality:** XX% (how well-written is the code?) + - **Completeness:** XX% (does it fulfill requirements?) + - **Risk Level:** XX% (how risky is this change?) + - **Test Coverage:** XX% (are changes adequately tested?) + + ### Merge Readiness: + - [ ] All critical issues resolved + - [ ] SOLID average score >= 6.0 + - [ ] Overall confidence >= 60% + - [ ] No security concerns + - [ ] Tests present and passing (if applicable) + + ### Verdict: + **MERGE** | **MERGE WITH FIXES** | **DO NOT MERGE** + + One-sentence explanation of the verdict. + + --- + + **Review Guidelines:** + 1. Check the PR description for linked issues ("Fixes #123", "Closes #456", etc.) and verify the implementation + 2. Be extremely specific with file paths and line numbers + 3. Confidence scores should reflect how certain you are - use "Low" when unsure + 4. If you have nothing meaningful to add to a section, write "None identified" instead of omitting it + 5. Always provide actionable fixes, never just complaints diff --git a/.npmignore b/.npmignore new file mode 100644 index 0000000..fc9f1c4 --- /dev/null +++ b/.npmignore @@ -0,0 +1,29 @@ +# Source files (we publish compiled dist/) +src/ + +# Development +node_modules/ +.github/ +CLAUDE.md +AGENTS.md +.env +.env.local + +# Build artifacts +dist/**/*.test.js +dist/**/*.test.d.ts +*.log + +# IDE +.vscode/ +.idea/ +*.swp +*.swo + +# Testing +coverage/ +.nyc_output/ + +# OS +.DS_Store +Thumbs.db diff --git a/AGENTS.md b/AGENTS.md index 3ab1457..7a4bd59 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,4 +1,4 @@ -# Agent Guidelines for workflow-automator +# Agent Guidelines for ActionFlow This document provides guidelines for AI agents working on this repository. diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..738c9f6 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 OpenStaticFish + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index 32e30bc..357fdd9 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Workflow Automator +# ActionFlow Interactive TUI for installing curated GitHub Actions workflows with a cyberpunk aesthetic. @@ -30,8 +30,8 @@ bun run src/tui/index.tsx Or install globally: ```bash -bun link -workflow-automator +bun install -g @openstaticfish/actionflow +actionflow ``` ## Keyboard Shortcuts @@ -50,7 +50,7 @@ workflow-automator ``` ┌─────────────────────────────────────────────────────────────────┐ -│ ⚡ WORKFLOW AUTOMATOR v1.0 Category: [opencode â–ŧ] │ +│ ⚡ ACTIONFLOW v0.1.0 Category: [opencode â–ŧ] │ ├──────────────────â”Ŧ──────────────────────────────────────────────┤ │ 🌲 Tree │ ┌─ Workflow Details ──────────────────────┐│ │ ▾ pr │ │ 🔍 OpenCode AI PR Review ││ diff --git a/package.json b/package.json index b1f5bf9..c64b48c 100644 --- a/package.json +++ b/package.json @@ -1,19 +1,59 @@ { - "name": "workflow-automator", - "module": "src/tui/index.tsx", - "type": "module", - "private": true, + "name": "@openstaticfish/actionflow", + "version": "0.1.0", + "description": "A terminal UI tool for managing and installing GitHub Actions workflow templates", + "license": "MIT", + "author": "OpenStaticFish ", + "repository": { + "type": "git", + "url": "https://github.com/openstaticfish/actionflow.git" + }, + "homepage": "https://github.com/openstaticfish/actionflow#readme", + "bugs": { + "url": "https://github.com/openstaticfish/actionflow/issues" + }, + "keywords": [ + "github-actions", + "workflow", + "cli", + "terminal", + "tui", + "automation", + "ci-cd", + "templates" + ], + "module": "./dist/index.js", + "types": "./dist/index.d.ts", + "exports": { + ".": { + "import": "./dist/index.js", + "types": "./dist/index.d.ts" + } + }, "bin": { - "workflow-automator": "./src/tui/index.tsx" + "actionflow": "./dist/index.js", + "af": "./dist/index.js" + }, + "files": [ + "dist", + "workflows", + "README.md", + "LICENSE" + ], + "engines": { + "bun": ">=1.0.0" }, "scripts": { "start": "bun run src/tui/index.tsx", "build": "bun build src/tui/index.tsx --outdir=dist --target=bun", + "build:types": "tsc --declaration --emitDeclarationOnly --outDir dist", + "prepublishOnly": "bun run build && bun run build:types", "test": "bun test" }, "devDependencies": { "@types/bun": "latest", - "@types/react": "^18.2.0" + "@types/react": "^18.2.0", + "typescript": "^5.0.0" }, "peerDependencies": { "typescript": "^5" diff --git a/src/tui/components/Header.tsx b/src/tui/components/Header.tsx index 843a68b..d30de13 100644 --- a/src/tui/components/Header.tsx +++ b/src/tui/components/Header.tsx @@ -36,7 +36,7 @@ export function Header({ alignItems="center" > - ⚡ WORKFLOW AUTOMATOR + ⚡ ACTIONFLOW diff --git a/tsconfig.json b/tsconfig.json index bfa0fea..ac576f8 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -3,7 +3,7 @@ // Environment setup & latest features "lib": ["ESNext"], "target": "ESNext", - "module": "Preserve", + "module": "ESNext", "moduleDetection": "force", "jsx": "react-jsx", "allowJs": true, @@ -12,7 +12,11 @@ "moduleResolution": "bundler", "allowImportingTsExtensions": true, "verbatimModuleSyntax": true, - "noEmit": true, + "noEmit": false, + "declaration": true, + "declarationMap": true, + "outDir": "./dist", + "rootDir": "./src", // Best practices "strict": true, @@ -25,5 +29,7 @@ "noUnusedLocals": false, "noUnusedParameters": false, "noPropertyAccessFromIndexSignature": false - } + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "dist"] } diff --git a/workflows/opencode/opencode/opencode.yml b/workflows/opencode/opencode/opencode.yml index 5e31650..3cd58c2 100644 --- a/workflows/opencode/opencode/opencode.yml +++ b/workflows/opencode/opencode/opencode.yml @@ -2,8 +2,8 @@ # id: opencode/opencode # category: opencode # type: set -# name: OpenCode Slash Commands -# description: Responds to /oc and /opencode commands in issues and PRs +# name: OpenCode AI Slash Commands +# description: OpenCode AI slash command handler (/oc, /opencode) # secrets: # - name: KIMI_API_KEY # description: API key for OpenCode AI service @@ -12,12 +12,10 @@ # triggers: [issue_comment, pull_request_review_comment] # variants: # - name: standard -# description: Uses standard GitHub Actions with direct API calls -# - name: nix -# description: Uses Nix for reproducible environment +# description: Uses OpenCode GitHub Action # --- -name: OpenCode Slash Commands +name: OpenCode AI Slash Commands on: issue_comment: @@ -26,84 +24,30 @@ on: types: [created] jobs: - handle-command: + opencode: + if: | + contains(github.event.comment.body, ' /oc') || + startsWith(github.event.comment.body, '/oc') || + contains(github.event.comment.body, ' /opencode') || + startsWith(github.event.comment.body, '/opencode') runs-on: ubuntu-latest - if: github.event.comment.body =~ /^\/(oc|opencode)\b/ - + permissions: + id-token: write + contents: write + pull-requests: write + issues: write steps: - name: Checkout repository uses: actions/checkout@v4 - - name: Parse command - id: parse + - name: Configure git run: | - COMMENT_BODY="${{ github.event.comment.body }}" - - # Extract command after /oc or /opencode - if [[ "$COMMENT_BODY" =~ ^/oc\s*(.*) ]]; then - COMMAND="${BASH_REMATCH[1]}" - elif [[ "$COMMENT_BODY" =~ ^/opencode\s*(.*) ]]; then - COMMAND="${BASH_REMATCH[1]}" - fi - - echo "command=$COMMAND" >> $GITHUB_OUTPUT - echo "Parsed command: $COMMAND" + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" - - name: Gather context - id: context - run: | - # Get issue/PR context - if [ "${{ github.event.issue.number }}" != "" ]; then - echo "type=issue" >> $GITHUB_OUTPUT - echo "number=${{ github.event.issue.number }}" >> $GITHUB_OUTPUT - else - echo "type=pr" >> $GITHUB_OUTPUT - echo "number=${{ github.event.pull_request.number }}" >> $GITHUB_OUTPUT - fi - - - name: Run OpenCode AI + - name: Run opencode + uses: anomalyco/opencode/github@latest env: KIMI_API_KEY: ${{ secrets.KIMI_API_KEY }} - COMMAND: ${{ steps.parse.outputs.command }} - CONTEXT_TYPE: ${{ steps.context.outputs.type }} - ISSUE_NUMBER: ${{ steps.context.outputs.number }} - run: | - # Build context for AI - PROMPT=$(cat < response.json - - cat response.json | jq -r '.choices[0].message.content' > response.txt - - - name: Post response - uses: actions/github-script@v7 with: - script: | - const fs = require('fs'); - const response = fs.readFileSync('response.txt', 'utf8'); - - const reply = `🤖 **OpenCode AI**\n\n${response}`; - - await github.rest.issues.createComment({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: ${{ steps.context.outputs.number }}, - body: reply - }); + model: kimi-for-coding/k2p5 diff --git a/workflows/opencode/pr/opencode-pr-nix.yml b/workflows/opencode/pr/opencode-pr-nix.yml index b46e576..6602809 100644 --- a/workflows/opencode/pr/opencode-pr-nix.yml +++ b/workflows/opencode/pr/opencode-pr-nix.yml @@ -73,44 +73,28 @@ jobs: - name: Run OpenCode AI Review env: KIMI_API_KEY: ${{ secrets.KIMI_API_KEY }} + PR_TITLE: ${{ github.event.pull_request.title }} + PR_DESCRIPTION: ${{ github.event.pull_request.body }} + PREVIOUS_COMMENTS: ${{ steps.previous-comments.outputs.result }} run: | nix develop --command bash -c ' DIFF_CONTENT=$(cat pr_diff.txt) - PREVIOUS_COMMENTS="${{ steps.previous-comments.outputs.result }}" - PROMPT=$(cat < prompt.json curl -X POST https://api.opencode.ai/v1/chat/completions \ -H "Authorization: Bearer $KIMI_API_KEY" \ -H "Content-Type: application/json" \ - -d "{ - \"model\": \"kimi-latest\", - \"messages\": [{\"role\": \"user\", \"content\": $(echo "$PROMPT" | jq -Rs .)}] - }" > review_response.json + -d @prompt.json > review_response.json cat review_response.json | jq -r ".choices[0].message.content" > review_output.txt ' diff --git a/workflows/opencode/pr/opencode-pr.yml b/workflows/opencode/pr/opencode-pr.yml index fa63f65..ad4d289 100644 --- a/workflows/opencode/pr/opencode-pr.yml +++ b/workflows/opencode/pr/opencode-pr.yml @@ -12,9 +12,7 @@ # triggers: [pull_request] # variants: # - name: standard -# description: Uses standard GitHub Actions with direct API calls -# - name: nix -# description: Uses Nix for reproducible environment +# description: Uses OpenCode GitHub Action # --- name: OpenCode AI PR Review @@ -24,102 +22,119 @@ on: types: [opened, synchronize, reopened, ready_for_review] jobs: - review: + opencode: + # Don't run on draft PRs; do run when they become ready_for_review. + if: ${{ github.event.pull_request.draft == false }} runs-on: ubuntu-latest - if: github.event.pull_request.draft == false - + timeout-minutes: 10 + permissions: + id-token: write + contents: write + pull-requests: write + issues: read + steps: - - name: Checkout code + - name: Checkout repository uses: actions/checkout@v4 with: fetch-depth: 0 - - name: Get PR diff - id: diff + - name: Configure git run: | - git diff origin/${{ github.base_ref }}...HEAD > pr_diff.txt - echo "diff_path=pr_diff.txt" >> $GITHUB_OUTPUT + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" - - name: Get previous review comments - id: previous-comments - uses: actions/github-script@v7 - with: - script: | - const comments = await github.rest.issues.listComments({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: context.issue.number - }); - const opencodeComments = comments.data.filter(c => - c.user.login === 'github-actions[bot]' && - c.body.includes('OpenCode AI Review') - ); - return opencodeComments.map(c => c.body).join('\n---\n'); - - - name: Run OpenCode AI Review + - name: Run opencode + uses: anomalyco/opencode/github@latest env: KIMI_API_KEY: ${{ secrets.KIMI_API_KEY }} - PR_DIFF: ${{ steps.diff.outputs.diff_path }} - PREVIOUS_COMMENTS: ${{ steps.previous-comments.outputs.result }} - PR_TITLE: ${{ github.event.pull_request.title }} - PR_DESCRIPTION: ${{ github.event.pull_request.body }} - run: | - # Read the diff file - DIFF_CONTENT=$(cat "$PR_DIFF") - - # Create the review prompt - PROMPT=$(cat < review_response.json - - # Extract and post review - REVIEW_TEXT=$(cat review_response.json | jq -r '.choices[0].message.content') - - echo "$REVIEW_TEXT" > review_output.txt - cat review_output.txt - - - name: Post review comment - uses: actions/github-script@v7 with: - script: | - const fs = require('fs'); - const reviewText = fs.readFileSync('review_output.txt', 'utf8'); - const formattedReview = `## OpenCode AI Review 🤖\n\n${reviewText}`; + model: kimi-for-coding/k2p5 + prompt: | + You are reviewing a pull request. Analyze the code changes and output your review in the following STRICT STRUCTURE: + + --- + + ## 📋 Summary + First, check if the PR description mentions any linked issues (e.g., "Closes #123", "Fixes #456", "Resolves #789"). + + If linked issues are found: + - Mention the issue number(s) explicitly + - Verify the PR actually implements what the issue(s) requested + - State whether the implementation fully satisfies the issue requirements + + Then provide 2-3 sentences summarizing the PR purpose, scope, and overall quality. + + ## 🔴 Critical Issues (Must Fix - Blocks Merge) + Only issues that could cause crashes, security vulnerabilities, data loss, or major bugs. + + For each issue, use this exact format: + ``` + **[CRITICAL]** `File:Line` - Issue Title + **Confidence:** High|Medium|Low (how sure you are this is a real problem) + **Description:** Clear explanation of the issue + **Impact:** What could go wrong if merged + **Suggested Fix:** Specific code changes needed + ``` + + ## âš ī¸ High Priority Issues (Should Fix) + Significant code quality issues, potential bugs, or architectural problems. + + Same format as Critical, but with **[HIGH]** prefix. + + ## 💡 Medium Priority Issues (Nice to Fix) + Style issues, minor optimizations, or code clarity improvements. - await github.rest.issues.createComment({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: context.issue.number, - body: formattedReview - }); + Same format, with **[MEDIUM]** prefix. + + ## â„šī¸ Low Priority Suggestions (Optional) + Minor suggestions, documentation improvements, or subjective preferences. + + Same format, with **[LOW]** prefix. + + ## 📊 SOLID Principles Score + | Principle | Score | Notes | + |-----------|-------|-------| + | Single Responsibility | 0-10 | Brief justification | + | Open/Closed | 0-10 | Brief justification | + | Liskov Substitution | 0-10 | Brief justification | + | Interface Segregation | 0-10 | Brief justification | + | Dependency Inversion | 0-10 | Brief justification | + | **Average** | **X.X** | | + + ## đŸŽ¯ Final Assessment + + ### Overall Confidence Score: XX% + Rate your confidence in this PR being ready to merge (0-100%). + **How to interpret:** + - 0-30%: Major concerns, do not merge without significant rework + - 31-60%: Moderate concerns, several issues need addressing + - 61-80%: Minor concerns, mostly ready with some fixes + - 81-100%: High confidence, ready to merge or with trivial fixes + + ### Confidence Breakdown: + - **Code Quality:** XX% (how well-written is the code?) + - **Completeness:** XX% (does it fulfill requirements?) + - **Risk Level:** XX% (how risky is this change?) + - **Test Coverage:** XX% (are changes adequately tested?) + + ### Merge Readiness: + - [ ] All critical issues resolved + - [ ] SOLID average score >= 6.0 + - [ ] Overall confidence >= 60% + - [ ] No security concerns + - [ ] Tests present and passing (if applicable) + + ### Verdict: + **MERGE** | **MERGE WITH FIXES** | **DO NOT MERGE** + + One-sentence explanation of the verdict. + + --- + + **Review Guidelines:** + 1. Check the PR description for linked issues ("Fixes #123", "Closes #456", etc.) and verify the implementation + 2. Be extremely specific with file paths and line numbers + 3. Confidence scores should reflect how certain you are - use "Low" when unsure + 4. If you have nothing meaningful to add to a section, write "None identified" instead of omitting it + 5. Always provide actionable fixes, never just complaints diff --git a/workflows/opencode/triage/opencode-triage.yml b/workflows/opencode/triage/opencode-triage.yml index bcf418d..3be020a 100644 --- a/workflows/opencode/triage/opencode-triage.yml +++ b/workflows/opencode/triage/opencode-triage.yml @@ -2,8 +2,8 @@ # id: opencode/opencode-triage # category: opencode # type: set -# name: OpenCode Issue Triage -# description: AI-powered issue classification and initial response for new issues +# name: OpenCode AI Issue Triage +# description: Automated issue triage using OpenCode AI # secrets: # - name: KIMI_API_KEY # description: API key for OpenCode AI service @@ -12,10 +12,10 @@ # triggers: [issues] # variants: # - name: standard -# description: Uses standard GitHub Actions +# description: Uses OpenCode GitHub Action # --- -name: OpenCode Issue Triage +name: OpenCode AI Issue Triage on: issues: @@ -24,119 +24,58 @@ on: jobs: triage: runs-on: ubuntu-latest - + permissions: + id-token: write + contents: write + pull-requests: write + issues: write steps: - name: Check account age - id: account-check + id: check uses: actions/github-script@v7 with: script: | - const { data: user } = await github.rest.users.getByUsername({ + const user = await github.rest.users.getByUsername({ username: context.payload.issue.user.login }); - - const createdAt = new Date(user.created_at); - const now = new Date(); - const daysOld = (now - createdAt) / (1000 * 60 * 60 * 24); - - console.log(`Account is ${daysOld} days old`); - - if (daysOld < 30) { - console.log('Account is new, skipping AI triage'); - return 'skip'; - } - return 'process'; + const created = new Date(user.data.created_at); + const days = (Date.now() - created) / (1000 * 60 * 60 * 24); + return days >= 30; + result-encoding: string - - name: Checkout repository - if: steps.account-check.outputs.result == 'process' - uses: actions/checkout@v4 + - uses: actions/checkout@v4 + if: steps.check.outputs.result == 'true' - - name: Analyze issue - if: steps.account-check.outputs.result == 'process' - env: - KIMI_API_KEY: ${{ secrets.KIMI_API_KEY }} - ISSUE_TITLE: ${{ github.event.issue.title }} - ISSUE_BODY: ${{ github.event.issue.body }} + - name: Configure git + if: steps.check.outputs.result == 'true' run: | - PROMPT=$(cat < analysis.json - - cat analysis.json | jq -r '.choices[0].message.content' > analysis.txt - cat analysis.txt - - - name: Apply labels and respond - if: steps.account-check.outputs.result == 'process' - uses: actions/github-script@v7 + - uses: anomalyco/opencode/github@latest + if: steps.check.outputs.result == 'true' + env: + KIMI_API_KEY: ${{ secrets.KIMI_API_KEY }} with: - script: | - const fs = require('fs'); - const content = fs.readFileSync('analysis.txt', 'utf8'); - - // Try to parse JSON response - let analysis; - try { - // Extract JSON from markdown code block if present - const jsonMatch = content.match(/```json\n?([\s\S]*?)\n?```/) || - content.match(/\{[\s\S]*\}/); - analysis = JSON.parse(jsonMatch ? jsonMatch[1] || jsonMatch[0] : content); - } catch (e) { - console.log('Failed to parse JSON, using raw response'); - analysis = { - classification: 'Unknown', - response: content - }; - } - - // Apply classification label - const labelMap = { - 'Bug': 'bug', - 'Feature Request': 'enhancement', - 'Question': 'question' - }; - - if (labelMap[analysis.classification]) { - await github.rest.issues.addLabels({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: context.issue.number, - labels: [labelMap[analysis.classification]] - }); - } - - // Post AI response - const response = analysis.response || content; - await github.rest.issues.createComment({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: context.issue.number, - body: `🤖 **OpenCode AI Triage**\n\n**Classification:** ${analysis.classification || 'Unknown'}\n**Priority:** ${analysis.priority || 'Unknown'}\n\n${response}` - }); + model: kimi-for-coding/k2p5 + prompt: | + Analyze this issue. You have access to the codebase context. + **CRITICAL: Your only allowed action is to post a COMMENT on the issue. DO NOT create branches, pull requests, or attempt to modify the codebase.** + + 1. **Classify**: Determine if this is a Bug, Feature Request, or Question. + 2. **Validate & Request Info**: + - **Missing Data**: If critical information is needed to understand or reproduce the issue (e.g., reproduction steps, crash logs, version numbers, screenshots), explicitly ask the user to provide it. + 3. **Analyze**: + - If a stack trace or error is provided, analyze the codebase to find the root cause and provide code pointers. + - If it's a feature request, briefly summarize the architectural impact. + - **Check for Scope**: Determine if this issue is too broad or complex and should be broken down into smaller, manageable sub-issues. Consider breaking up if: + - Multiple unrelated changes or features are requested + - The scope spans multiple subsystems (e.g., graphics + physics + UI) + - The issue description is vague or covers multiple distinct problems + - The implementation would require multiple independent PRs + 4. **Action**: + - Your response MUST be a comment on the issue. + - If you can provide a potential fix or documentation link, describe it in the comment but do NOT implement it. + - If you need more info, specify exactly what is missing. + - If the issue is vague, spam, or you have nothing valuable to add: **DO NOT COMMENT**. + - If the issue should be broken into sub-issues, clearly state this and suggest specific sub-tasks or areas to split.