diff --git a/.github/workflows/ai-batch-analyze-issues.yml b/.github/workflows/ai-batch-analyze-issues.yml new file mode 100644 index 00000000..c81c0c08 --- /dev/null +++ b/.github/workflows/ai-batch-analyze-issues.yml @@ -0,0 +1,73 @@ +name: AI Batch Analyze Issues + +on: + workflow_dispatch: + inputs: + mode: + description: '分析模式' + required: true + type: choice + options: + - 'recent' # 最近 10 个 issue + - 'open' # 所有打开的 issue + - 'all' # 所有 issue(慎用) + default: 'recent' + +permissions: + issues: write + contents: read + +jobs: + analyze: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '20.x' + + - name: Install GitHub CLI + run: | + gh --version || (curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | sudo dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg + echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null + sudo apt update + sudo apt install gh) + + - name: Batch Analyze Issues + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + MODE="${{ github.event.inputs.mode }}" + + # 获取 issue 列表 + if [ "$MODE" = "recent" ]; then + echo "📊 分析最近 10 个 issue..." + ISSUES=$(gh issue list --limit 10 --json number --jq '.[].number') + elif [ "$MODE" = "open" ]; then + echo "📊 分析所有打开的 issue..." + ISSUES=$(gh issue list --state open --json number --jq '.[].number') + else + echo "📊 分析所有 issue(这可能需要很长时间)..." + ISSUES=$(gh issue list --state all --limit 100 --json number --jq '.[].number') + fi + + # 为每个 issue 添加 AI 分析评论 + for issue_num in $ISSUES; do + echo "🤖 分析 Issue #$issue_num..." + + # 获取 issue 内容 + ISSUE_BODY=$(gh issue view $issue_num --json body --jq '.body') + ISSUE_TITLE=$(gh issue view $issue_num --json title --jq '.title') + + # 添加触发评论 + gh issue comment $issue_num --body "@ai-helper 请帮我分析这个 issue" || true + + # 避免 API 限制 + sleep 2 + done + + echo "✅ 批量分析完成!" + echo "查看结果:https://github.com/${{ github.repository }}/issues" diff --git a/.github/workflows/ai-issue-helper.yml b/.github/workflows/ai-issue-helper.yml new file mode 100644 index 00000000..86bc95e4 --- /dev/null +++ b/.github/workflows/ai-issue-helper.yml @@ -0,0 +1,85 @@ +name: AI Issue Helper + +on: + issue_comment: + types: [created] + +permissions: + issues: write + contents: read + models: read + +jobs: + ai-helper: + runs-on: ubuntu-latest + # 只在真实用户提到 @ai-helper 时触发,忽略机器人评论 + if: | + contains(github.event.comment.body, '@ai-helper') && + github.event.comment.user.type != 'Bot' + steps: + - name: Checkout Repository + uses: actions/checkout@v4 + + - name: Get Issue Details + id: issue + uses: actions/github-script@v7 + with: + script: | + const issue = await github.rest.issues.get({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number + }); + + // 限制长度,避免超过 token 限制 + const maxLength = 1000; + const truncate = (str, max) => { + if (!str) return ''; + return str.length > max ? str.substring(0, max) + '...[内容过长已截断]' : str; + }; + + core.exportVariable('ISSUE_TITLE', truncate(issue.data.title || '', 200)); + core.exportVariable('ISSUE_BODY', truncate(issue.data.body || '', maxLength)); + core.exportVariable('COMMENT_BODY', truncate(context.payload.comment.body || '', 500)); + core.exportVariable('ISSUE_NUMBER', context.issue.number); + + - name: Create Prompt + id: prompt + run: | + cat > prompt.txt << 'PROMPT_EOF' + Issue #${{ env.ISSUE_NUMBER }} + + 标题: ${{ env.ISSUE_TITLE }} + + 内容: ${{ env.ISSUE_BODY }} + + 评论: ${{ env.COMMENT_BODY }} + + 请搜索项目代码并提供解决方案。 + PROMPT_EOF + + - name: AI Analysis + uses: actions/ai-inference@v1 + id: ai + with: + model: 'gpt-4o' + enable-github-mcp: true + max-tokens: 1500 + system-prompt: | + 你是 ECS Framework (TypeScript ECS 框架) 的 AI 助手。 + 主要代码在 packages/core/src。 + 搜索相关代码后,用中文简洁回答问题,包含问题分析、解决方案和代码引用。 + prompt-file: prompt.txt + + - name: Post AI Response + env: + AI_RESPONSE: ${{ steps.ai.outputs.response }} + uses: actions/github-script@v7 + with: + script: | + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + body: process.env.AI_RESPONSE + }); diff --git a/.github/workflows/ai-issue-moderator.yml b/.github/workflows/ai-issue-moderator.yml new file mode 100644 index 00000000..a50bf6f5 --- /dev/null +++ b/.github/workflows/ai-issue-moderator.yml @@ -0,0 +1,56 @@ +name: AI Issue Moderator + +on: + issues: + types: [opened] + issue_comment: + types: [created] + +permissions: + issues: write + contents: read + models: read + +jobs: + moderate: + runs-on: ubuntu-latest + steps: + - name: Check Content + uses: actions/ai-inference@v1 + id: check + with: + model: 'gpt-4o-mini' + system-prompt: | + 你是一个内容审查助手。 + 检查内容是否包含: + 1. 垃圾信息或广告 + 2. 恶意或攻击性内容 + 3. 与项目完全无关的内容 + + 只返回 "SPAM" 或 "OK",不要其他内容。 + prompt: | + 标题:${{ github.event.issue.title || github.event.comment.body }} + + 内容: + ${{ github.event.issue.body || github.event.comment.body }} + + - name: Mark as Spam + if: contains(steps.check.outputs.response, 'SPAM') + uses: actions/github-script@v7 + with: + script: | + // 添加 spam 标签 + github.rest.issues.addLabels({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + labels: ['spam'] + }); + + // 添加评论 + github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + body: '🤖 这个内容被 AI 检测为可能的垃圾内容。如果这是误判,请联系维护者。\n\n🤖 This content was detected as potential spam by AI. If this is a false positive, please contact the maintainers.' + }); diff --git a/.github/workflows/batch-label-issues.yml b/.github/workflows/batch-label-issues.yml new file mode 100644 index 00000000..24a25058 --- /dev/null +++ b/.github/workflows/batch-label-issues.yml @@ -0,0 +1,160 @@ +name: Batch Label Issues + +on: + workflow_dispatch: + inputs: + mode: + description: '标签模式' + required: true + type: choice + options: + - 'recent' # 最近 20 个 issue + - 'open' # 所有打开的 issue + - 'unlabeled' # 只处理没有标签的 issue + - 'all' # 所有 issue(慎用) + default: 'recent' + + skip_labeled: + description: '跳过已有标签的 issue' + required: false + type: boolean + default: true + +permissions: + issues: write + contents: read + +jobs: + batch-label: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '20.x' + + - name: Batch Label Issues + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + MODE="${{ github.event.inputs.mode }}" + SKIP_LABELED="${{ github.event.inputs.skip_labeled }}" + + echo "📊 开始批量打标签..." + echo "模式: $MODE" + echo "跳过已标签: $SKIP_LABELED" + + # 获取 issue 列表 + if [ "$MODE" = "recent" ]; then + echo "📋 获取最近 20 个 issue..." + ISSUES=$(gh issue list --limit 20 --json number,labels,title,body --jq '.[] | {number, labels: [.labels[].name], title, body}') + elif [ "$MODE" = "open" ]; then + echo "📋 获取所有打开的 issue..." + ISSUES=$(gh issue list --state open --json number,labels,title,body --jq '.[] | {number, labels: [.labels[].name], title, body}') + elif [ "$MODE" = "unlabeled" ]; then + echo "📋 获取没有标签的 issue..." + ISSUES=$(gh issue list --state all --json number,labels,title,body --jq '.[] | select(.labels | length == 0) | {number, labels: [.labels[].name], title, body}') + else + echo "📋 获取所有 issue(限制 100 个)..." + ISSUES=$(gh issue list --state all --limit 100 --json number,labels,title,body --jq '.[] | {number, labels: [.labels[].name], title, body}') + fi + + # 临时文件 + echo "$ISSUES" > /tmp/issues.json + + # 处理每个 issue + cat /tmp/issues.json | jq -c '.' | while read -r issue; do + ISSUE_NUM=$(echo "$issue" | jq -r '.number') + EXISTING_LABELS=$(echo "$issue" | jq -r '.labels | join(",")') + TITLE=$(echo "$issue" | jq -r '.title') + BODY=$(echo "$issue" | jq -r '.body') + + echo "" + echo "🔍 处理 Issue #$ISSUE_NUM: $TITLE" + echo " 现有标签: $EXISTING_LABELS" + + # 跳过已有标签的 issue + if [ "$SKIP_LABELED" = "true" ] && [ ! -z "$EXISTING_LABELS" ]; then + echo " ⏭️ 跳过(已有标签)" + continue + fi + + # 分析内容并打标签 + LABELS_TO_ADD="" + + # 检测 bug + if echo "$TITLE $BODY" | grep -iE "(bug|错误|崩溃|crash|error|exception|问题|fix)" > /dev/null; then + LABELS_TO_ADD="$LABELS_TO_ADD bug" + echo " 🐛 检测到: bug" + fi + + # 检测 feature request + if echo "$TITLE $BODY" | grep -iE "(feature|功能|enhancement|improve|优化|建议|新增|添加|add)" > /dev/null; then + LABELS_TO_ADD="$LABELS_TO_ADD enhancement" + echo " ✨ 检测到: enhancement" + fi + + # 检测 question + if echo "$TITLE $BODY" | grep -iE "(question|疑问|how to|如何|怎么|为什么|why|咨询|\?|?)" > /dev/null; then + LABELS_TO_ADD="$LABELS_TO_ADD question" + echo " ❓ 检测到: question" + fi + + # 检测 documentation + if echo "$TITLE $BODY" | grep -iE "(doc|文档|readme|guide|tutorial|教程|说明)" > /dev/null; then + LABELS_TO_ADD="$LABELS_TO_ADD documentation" + echo " 📖 检测到: documentation" + fi + + # 检测 performance + if echo "$TITLE $BODY" | grep -iE "(performance|性能|slow|慢|lag|卡顿|optimize|优化)" > /dev/null; then + LABELS_TO_ADD="$LABELS_TO_ADD performance" + echo " ⚡ 检测到: performance" + fi + + # 检测 core + if echo "$TITLE $BODY" | grep -iE "(@esengine/ecs-framework|packages/core|core package|核心包)" > /dev/null; then + LABELS_TO_ADD="$LABELS_TO_ADD core" + echo " 🎯 检测到: core" + fi + + # 检测 editor + if echo "$TITLE $BODY" | grep -iE "(editor|编辑器|tauri)" > /dev/null; then + LABELS_TO_ADD="$LABELS_TO_ADD editor" + echo " 🎨 检测到: editor" + fi + + # 检测 network + if echo "$TITLE $BODY" | grep -iE "(network|网络|multiplayer|多人|同步)" > /dev/null; then + LABELS_TO_ADD="$LABELS_TO_ADD network" + echo " 🌐 检测到: network" + fi + + # 检测 help wanted + if echo "$TITLE $BODY" | grep -iE "(help wanted|需要帮助|求助)" > /dev/null; then + LABELS_TO_ADD="$LABELS_TO_ADD help wanted" + echo " 🆘 检测到: help wanted" + fi + + # 添加标签 + if [ ! -z "$LABELS_TO_ADD" ]; then + echo " ✅ 添加标签: $LABELS_TO_ADD" + for label in $LABELS_TO_ADD; do + gh issue edit $ISSUE_NUM --add-label "$label" 2>&1 | grep -v "already exists" || true + done + echo " 💬 添加说明评论..." + gh issue comment $ISSUE_NUM --body $'🤖 自动标签系统检测到此 issue 并添加了相关标签。如有误判,请告知维护者。\n\n🤖 Auto-labeling system detected and labeled this issue. Please let maintainers know if this is incorrect.' || true + else + echo " ℹ️ 未检测到明确类型" + fi + + # 避免 API 限制 + sleep 1 + done + + echo "" + echo "✅ 批量标签完成!" + echo "查看结果: https://github.com/${{ github.repository }}/issues"