[new tool] @agent-tools/kafka — Apache Kafka producer/consumer client for event streaming #214
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: PR Review | |
| on: | |
| pull_request: | |
| types: [opened] | |
| issues: | |
| types: [opened] | |
| permissions: | |
| contents: read | |
| pull-requests: write | |
| issues: write | |
| jobs: | |
| review-pr: | |
| if: github.event_name == 'pull_request' | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Use Node.js 22 | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: 22 | |
| - name: Install dependencies | |
| run: npm install | |
| - name: Build | |
| run: npm run build | |
| - name: Test | |
| run: npm test | |
| - name: Require issue reference | |
| uses: actions/github-script@v7 | |
| with: | |
| script: | | |
| const body = context.payload.pull_request.body || ''; | |
| const hasRef = /(?:closes|fixes|resolves)\s+#\d+/i.test(body); | |
| if (!hasRef) { | |
| await github.rest.issues.createComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: context.issue.number, | |
| body: '❌ **PR rejected — no issue reference.**\n\nYour PR body must include `Closes #N` (or `Fixes #N` / `Resolves #N`) linking to an open issue. Every PR must solve a tracked issue.\n\nClose this PR, add the reference, and resubmit.', | |
| }); | |
| await github.rest.pulls.update({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| pull_number: context.issue.number, | |
| state: 'closed', | |
| }); | |
| core.setFailed('PR must reference an issue with Closes #N'); | |
| } | |
| - name: Check for common issues | |
| run: | | |
| echo "## Automated Review Checklist" > /tmp/review.md | |
| echo "" >> /tmp/review.md | |
| # Check if tests exist for new files | |
| changed_src=$(git diff --name-only origin/main...HEAD -- 'packages/*/src/*.ts' ':!packages/*/src/__tests__/*' ':!packages/*/src/index.ts' || true) | |
| if [ -n "$changed_src" ]; then | |
| echo "### Source files changed:" >> /tmp/review.md | |
| echo '```' >> /tmp/review.md | |
| echo "$changed_src" >> /tmp/review.md | |
| echo '```' >> /tmp/review.md | |
| echo "" >> /tmp/review.md | |
| missing_tests="" | |
| for f in $changed_src; do | |
| pkg_dir=$(echo "$f" | cut -d'/' -f1-2) | |
| base=$(basename "$f" .ts) | |
| test_file="$pkg_dir/src/__tests__/$base.test.ts" | |
| if [ ! -f "$test_file" ]; then | |
| missing_tests="$missing_tests\n- \`$f\` -> missing \`$test_file\`" | |
| fi | |
| done | |
| if [ -n "$missing_tests" ]; then | |
| echo "### ⚠️ Missing test files:" >> /tmp/review.md | |
| echo -e "$missing_tests" >> /tmp/review.md | |
| else | |
| echo "### ✅ All changed source files have corresponding tests" >> /tmp/review.md | |
| fi | |
| fi | |
| echo "" >> /tmp/review.md | |
| # Check for any types | |
| any_count=$(git diff origin/main...HEAD -- '*.ts' | grep -c ': any' || true) | |
| if [ "$any_count" -gt 0 ]; then | |
| echo "### ⚠️ Found $any_count uses of \`: any\` in diff — prefer \`unknown\` with type narrowing" >> /tmp/review.md | |
| else | |
| echo "### ✅ No \`: any\` types found" >> /tmp/review.md | |
| fi | |
| echo "" >> /tmp/review.md | |
| echo "---" >> /tmp/review.md | |
| echo "*Build: ✅ Pass | Tests: ✅ Pass | Typecheck: ✅ Pass*" >> /tmp/review.md | |
| cat /tmp/review.md | |
| - name: Post review comment | |
| if: always() | |
| uses: actions/github-script@v7 | |
| with: | |
| script: | | |
| const fs = require('fs'); | |
| let body; | |
| try { | |
| body = fs.readFileSync('/tmp/review.md', 'utf8'); | |
| } catch { | |
| body = '## Automated Review\n\n⚠️ Review script did not complete. Check CI logs.'; | |
| } | |
| const comments = await github.rest.issues.listComments({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: context.issue.number, | |
| }); | |
| const botComment = comments.data.find(c => | |
| c.user.type === 'Bot' && c.body.includes('Automated Review Checklist') | |
| ); | |
| if (botComment) { | |
| await github.rest.issues.updateComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| comment_id: botComment.id, | |
| body, | |
| }); | |
| } else { | |
| await github.rest.issues.createComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: context.issue.number, | |
| body, | |
| }); | |
| } | |
| triage-issue: | |
| if: github.event_name == 'issues' | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Auto-label issues | |
| uses: actions/github-script@v7 | |
| with: | |
| script: | | |
| const title = context.payload.issue.title.toLowerCase(); | |
| const body = (context.payload.issue.body || '').toLowerCase(); | |
| const text = title + ' ' + body; | |
| const labels = []; | |
| if (title.includes('[bug]') || text.includes('bug')) labels.push('bug'); | |
| if (title.includes('[feature]') || text.includes('feature request')) labels.push('enhancement'); | |
| if (title.includes('[new tool]')) { | |
| labels.push('new-tool'); | |
| labels.push('help wanted'); | |
| } | |
| if (body.includes('good first issue') || body.includes('beginner')) { | |
| labels.push('good first issue'); | |
| } | |
| // Tier detection | |
| const tier1 = ['token-counter', 'file-converter', 'retry', 'sandbox']; | |
| const tier2 = ['web-scraper', 'dom-query', 'browser', 'screenshot', 'perception']; | |
| const tier3 = ['self-extend', 'workflow', 'autonomy', 'shell', 'moe', 'pipeline', 'orchestrat']; | |
| if (tier1.some(k => text.includes(k))) labels.push('tier:utility'); | |
| if (tier2.some(k => text.includes(k))) labels.push('tier:perception'); | |
| if (tier3.some(k => text.includes(k))) labels.push('tier:autonomy'); | |
| // Category detection | |
| if (text.includes('integration') || text.includes('harness')) labels.push('integration'); | |
| if (text.includes('ci') || text.includes('workflow') || text.includes('pipeline')) labels.push('infrastructure'); | |
| const unique = [...new Set(labels)]; | |
| if (unique.length > 0) { | |
| await github.rest.issues.addLabels({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: context.issue.number, | |
| labels: unique, | |
| }); | |
| } | |
| // Validate issue follows a template | |
| const prefixes = ['[bug]', '[feature]', '[new tool]']; | |
| const hasPrefix = prefixes.some(p => title.startsWith(p)); | |
| const templateSections = { | |
| bug: ['## package', '## description', '## steps to reproduce'], | |
| feature: ['## package', '## description', '## use case'], | |
| newTool: ['## tool name', '## description', '## why it\'s useful'], | |
| }; | |
| let followsTemplate = false; | |
| if (title.startsWith('[bug]')) { | |
| followsTemplate = templateSections.bug.every(s => body.includes(s)); | |
| } else if (title.startsWith('[feature]')) { | |
| followsTemplate = templateSections.feature.every(s => body.includes(s)); | |
| } else if (title.startsWith('[new tool]')) { | |
| followsTemplate = templateSections.newTool.every(s => body.includes(s)); | |
| } | |
| const isOwner = context.payload.issue.author_association === 'OWNER'; | |
| if (!isOwner && (!hasPrefix || !followsTemplate)) { | |
| await github.rest.issues.createComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: context.issue.number, | |
| body: [ | |
| '❌ **Issue closed — does not follow an issue template.**', | |
| '', | |
| 'All issues must use one of the provided templates:', | |
| '- **Bug Report** — title starts with `[bug]`, includes Package, Description, Steps to Reproduce', | |
| '- **Feature Request** — title starts with `[feature]`, includes Package, Description, Use Case', | |
| '- **New Tool Proposal** — title starts with `[new tool]`, includes Tool Name, Description, Why It\'s Useful', | |
| '', | |
| 'Please [open a new issue](../../issues/new/choose) using the correct template.', | |
| ].join('\n'), | |
| }); | |
| await github.rest.issues.update({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: context.issue.number, | |
| state: 'closed', | |
| state_reason: 'not_planned', | |
| }); | |
| await github.rest.issues.addLabels({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: context.issue.number, | |
| labels: ['closed: non-compliant'], | |
| }); | |
| } |