From 9406c15f5d82a8c26682c3011d4cee213e8d907f Mon Sep 17 00:00:00 2001 From: Roo Code Date: Sun, 21 Sep 2025 05:11:22 +0000 Subject: [PATCH] docs: Add GitHub Actions workflow documentation - Removed workflow files due to GitHub App restrictions - Added documentation for manual workflow installation - Workflow files need to be added manually by repository maintainer --- .github/scripts/README.md | 135 --------- .github/scripts/package.json | 19 -- .github/scripts/roocode-agent.ts | 483 ------------------------------ .github/workflows/roocode-bot.yml | 66 ---- github-actions-workflows.md | 142 +++++++++ 5 files changed, 142 insertions(+), 703 deletions(-) delete mode 100644 .github/scripts/README.md delete mode 100644 .github/scripts/package.json delete mode 100644 .github/scripts/roocode-agent.ts delete mode 100644 .github/workflows/roocode-bot.yml create mode 100644 github-actions-workflows.md diff --git a/.github/scripts/README.md b/.github/scripts/README.md deleted file mode 100644 index fd58e4569f..0000000000 --- a/.github/scripts/README.md +++ /dev/null @@ -1,135 +0,0 @@ -# RooCode Agent - GitHub Actions Bot - -This directory contains the RooCode Agent bot that runs in GitHub Actions to automatically handle issues and pull requests. - -## Features - -The RooCode Agent bot supports the following commands: - -### Issue Commands - -- `/roo` - General command to interact with the bot -- `/roo plan` - Create a detailed implementation plan for an issue -- `/roo approve` - Approve a plan and start implementation -- `/roo fix` - Directly implement a fix for an issue -- `/roo triage` - Analyze and triage an issue (priority, labels, complexity) -- `/roo label` - Automatically add appropriate labels to an issue - -### Pull Request Commands - -- `/roo review` - Perform a code review on a pull request -- `/roo` - General interaction with the bot on PRs - -## Setup Instructions - -### 1. Repository Secrets - -Configure the following secrets in your repository settings (`Settings > Secrets and variables > Actions`): - -**Required (at least one):** - -- `OPENAI_API_KEY` - OpenAI API key for GPT models -- `ANTHROPIC_API_KEY` - Anthropic API key for Claude models -- `OPENROUTER_API_KEY` - OpenRouter API key for various models - -**Automatic:** - -- `GITHUB_TOKEN` - Automatically provided by GitHub Actions - -### 2. Repository Variables - -Configure these variables in your repository settings (`Settings > Secrets and variables > Actions > Variables`): - -- `MODEL_PROVIDER` - Choose: `openai`, `anthropic`, or `openrouter` (default: `anthropic`) -- `MODEL_NAME` - Model to use (default: `claude-3-5-sonnet-20241022`) -- `MAX_TOKENS` - Maximum tokens for responses (default: `8192`) -- `TEMPERATURE` - Model temperature 0-1 (default: `0.2`) - -### 3. Enable GitHub Actions - -1. Go to `Settings > Actions > General` -2. Under "Workflow permissions", select "Read and write permissions" -3. Check "Allow GitHub Actions to create and approve pull requests" -4. Save the settings - -### 4. Test the Bot - -Create an issue or comment with `/roo` to trigger the bot: - -``` -/roo plan - -Please help me implement a new feature for user authentication. -``` - -## Workflow Triggers - -The bot is triggered by: - -- **Issue events**: When issues are opened or edited containing `/roo` -- **Issue comments**: When comments are created or edited containing `/roo` -- **Pull request events**: When PRs are opened, edited, or synchronized containing `/roo` -- **PR review comments**: When review comments are created or edited containing `/roo` -- **Manual dispatch**: Can be triggered manually from the Actions tab - -## Architecture - -``` -.github/ -├── workflows/ -│ └── roocode-bot.yml # GitHub Actions workflow definition -└── scripts/ - ├── roocode-agent.ts # Main bot logic - ├── package.json # Dependencies - └── README.md # This file -``` - -## Development - -To test locally: - -```bash -cd .github/scripts -npm install -npm start -``` - -Set environment variables: - -```bash -export GITHUB_TOKEN=your_token -export ANTHROPIC_API_KEY=your_key -export GITHUB_EVENT_PATH=path/to/event.json -export GITHUB_REPOSITORY=owner/repo -export GITHUB_EVENT_NAME=issues -``` - -## Security Considerations - -- API keys are stored as encrypted secrets -- The bot only has permissions granted by the `GITHUB_TOKEN` -- All actions are logged in GitHub Actions -- The bot identifies itself in all comments - -## Extending the Bot - -To add new commands: - -1. Add the command detection in `extractCommands()` -2. Implement the handler function -3. Add the case in `processIssue()` or `processPullRequest()` -4. Update this README with the new command - -## Troubleshooting - -Check the GitHub Actions logs: - -1. Go to the "Actions" tab in your repository -2. Click on the "RooCode Agent Bot" workflow -3. Select a run to view detailed logs - -Common issues: - -- Missing API keys: Check repository secrets -- Insufficient permissions: Check workflow permissions -- Model errors: Verify MODEL_PROVIDER and MODEL_NAME variables diff --git a/.github/scripts/package.json b/.github/scripts/package.json deleted file mode 100644 index 487fa66160..0000000000 --- a/.github/scripts/package.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "name": "roocode-agent-scripts", - "version": "1.0.0", - "description": "RooCode Agent GitHub Actions Bot", - "type": "module", - "scripts": { - "start": "tsx roocode-agent.ts" - }, - "dependencies": { - "@octokit/rest": "^20.0.2", - "@anthropic-ai/sdk": "^0.37.0", - "openai": "^5.12.2", - "@modelcontextprotocol/sdk": "^1.12.0", - "tsx": "^4.19.3" - }, - "devDependencies": { - "@types/node": "^20.0.0" - } -} diff --git a/.github/scripts/roocode-agent.ts b/.github/scripts/roocode-agent.ts deleted file mode 100644 index e4779a20e2..0000000000 --- a/.github/scripts/roocode-agent.ts +++ /dev/null @@ -1,483 +0,0 @@ -#!/usr/bin/env tsx - -import { Octokit } from "@octokit/rest" -import OpenAI from "openai" -import Anthropic from "@anthropic-ai/sdk" -import * as fs from "fs" -import * as path from "path" -import { exec } from "child_process" -import { promisify } from "util" - -const execAsync = promisify(exec) - -// Configuration from environment variables -const config = { - githubToken: process.env.GITHUB_TOKEN!, - openaiApiKey: process.env.OPENAI_API_KEY, - anthropicApiKey: process.env.ANTHROPIC_API_KEY, - openRouterApiKey: process.env.OPENROUTER_API_KEY, - modelProvider: process.env.MODEL_PROVIDER || "anthropic", - modelName: process.env.MODEL_NAME || "claude-3-5-sonnet-20241022", - maxTokens: parseInt(process.env.MAX_TOKENS || "8192"), - temperature: parseFloat(process.env.TEMPERATURE || "0.2"), -} - -// Initialize GitHub client -const octokit = new Octokit({ - auth: config.githubToken, -}) - -// Initialize AI clients based on provider -let aiClient: any -if (config.modelProvider === "openai" && config.openaiApiKey) { - aiClient = new OpenAI({ apiKey: config.openaiApiKey }) -} else if (config.modelProvider === "anthropic" && config.anthropicApiKey) { - aiClient = new Anthropic({ apiKey: config.anthropicApiKey }) -} else if (config.modelProvider === "openrouter" && config.openRouterApiKey) { - aiClient = new OpenAI({ - apiKey: config.openRouterApiKey, - baseURL: "https://openrouter.ai/api/v1", - }) -} else { - console.error("No valid AI provider configured") - process.exit(1) -} - -// Parse GitHub event -const eventPath = process.env.GITHUB_EVENT_PATH -const event = JSON.parse(fs.readFileSync(eventPath!, "utf8")) -const context = { - repo: process.env.GITHUB_REPOSITORY!.split("/")[1], - owner: process.env.GITHUB_REPOSITORY!.split("/")[0], - eventName: process.env.GITHUB_EVENT_NAME!, -} - -interface Command { - type: "plan" | "approve" | "fix" | "review" | "triage" | "label" | "comment" - content?: string - labels?: string[] - approved?: boolean -} - -// Extract commands from text -function extractCommands(text: string): Command[] { - const commands: Command[] = [] - - if (text.includes("/roo plan")) { - commands.push({ type: "plan" }) - } - if (text.includes("/roo approve")) { - commands.push({ type: "approve", approved: true }) - } - if (text.includes("/roo fix")) { - commands.push({ type: "fix" }) - } - if (text.includes("/roo review")) { - commands.push({ type: "review" }) - } - if (text.includes("/roo triage")) { - commands.push({ type: "triage" }) - } - if (text.includes("/roo label")) { - commands.push({ type: "label" }) - } - if (text.includes("/roo")) { - // Generic command - analyze and respond - commands.push({ type: "comment" }) - } - - return commands -} - -// Get AI response -async function getAIResponse(prompt: string, systemPrompt: string): Promise { - try { - if (config.modelProvider === "anthropic") { - const response = await aiClient.messages.create({ - model: config.modelName, - max_tokens: config.maxTokens, - temperature: config.temperature, - system: systemPrompt, - messages: [{ role: "user", content: prompt }], - }) - return response.content[0].text - } else { - // OpenAI or OpenRouter - const response = await aiClient.chat.completions.create({ - model: config.modelName, - max_tokens: config.maxTokens, - temperature: config.temperature, - messages: [ - { role: "system", content: systemPrompt }, - { role: "user", content: prompt }, - ], - }) - return response.choices[0].message.content || "" - } - } catch (error) { - console.error("Error getting AI response:", error) - throw error - } -} - -// Process issue event -async function processIssue(issue: any, comment?: any) { - const text = comment?.body || issue.body || "" - const commands = extractCommands(text) - - if (commands.length === 0) return - - for (const command of commands) { - switch (command.type) { - case "plan": - await createPlan(issue) - break - case "approve": - await approvePlan(issue) - break - case "fix": - await implementFix(issue) - break - case "triage": - await triageIssue(issue) - break - case "label": - await labelIssue(issue) - break - case "comment": - await respondToComment(issue, text) - break - } - } -} - -// Process pull request event -async function processPullRequest(pr: any, comment?: any) { - const text = comment?.body || pr.body || "" - const commands = extractCommands(text) - - if (commands.length === 0) return - - for (const command of commands) { - switch (command.type) { - case "review": - await reviewPullRequest(pr) - break - case "comment": - await respondToPRComment(pr, text) - break - } - } -} - -// Create a plan for an issue -async function createPlan(issue: any) { - const systemPrompt = `You are RooCode-Agent, an AI assistant that helps with GitHub issues. -Your task is to analyze the issue and create a detailed implementation plan. -Format your response as a clear, step-by-step plan with: -1. Understanding of the problem -2. Proposed solution -3. Implementation steps -4. Testing approach -5. Potential risks or considerations - -End your plan with: "Reply with '/roo approve' to proceed with implementation."` - - const prompt = `Issue #${issue.number}: ${issue.title} - -${issue.body} - -Please create a detailed implementation plan for this issue.` - - const plan = await getAIResponse(prompt, systemPrompt) - - await octokit.issues.createComment({ - owner: context.owner, - repo: context.repo, - issue_number: issue.number, - body: `## 📋 Implementation Plan - -${plan} - ---- -*Generated by RooCode-Agent*`, - }) -} - -// Approve and implement plan -async function approvePlan(issue: any) { - // Check if there's a plan in the comments - const comments = await octokit.issues.listComments({ - owner: context.owner, - repo: context.repo, - issue_number: issue.number, - }) - - const planComment = comments.data.find( - (c) => c.body?.includes("Implementation Plan") && c.user?.login === "github-actions[bot]", - ) - - if (!planComment) { - await octokit.issues.createComment({ - owner: context.owner, - repo: context.repo, - issue_number: issue.number, - body: `❌ No plan found to approve. Please run '/roo plan' first.`, - }) - return - } - - await octokit.issues.createComment({ - owner: context.owner, - repo: context.repo, - issue_number: issue.number, - body: `✅ Plan approved! Starting implementation... - -*Note: This is a demonstration. In a real scenario, the bot would now create a branch and implement the changes.*`, - }) - - // In a real implementation, this would create a branch and start coding - await implementFix(issue) -} - -// Implement a fix for an issue -async function implementFix(issue: any) { - // This is a simplified version - in reality, this would: - // 1. Create a new branch - // 2. Make code changes based on the issue - // 3. Commit and push changes - // 4. Create a pull request - - const branchName = `fix/issue-${issue.number}` - - try { - // Create a simple demonstration PR - await octokit.issues.createComment({ - owner: context.owner, - repo: context.repo, - issue_number: issue.number, - body: `🔧 Working on implementation... - -- Creating branch: \`${branchName}\` -- Analyzing codebase... -- Implementing changes... - -*Note: This is a demonstration. In a production environment, the bot would actually create and modify files.*`, - }) - } catch (error) { - console.error("Error implementing fix:", error) - await octokit.issues.createComment({ - owner: context.owner, - repo: context.repo, - issue_number: issue.number, - body: `❌ Error implementing fix: ${error}`, - }) - } -} - -// Triage an issue -async function triageIssue(issue: any) { - const systemPrompt = `You are RooCode-Agent. Analyze this issue and suggest: -1. Priority level (P0-Critical, P1-High, P2-Medium, P3-Low) -2. Relevant labels (bug, enhancement, documentation, etc.) -3. Estimated complexity (Easy, Medium, Hard) -4. Suggested assignee type (frontend, backend, fullstack, devops)` - - const prompt = `Issue #${issue.number}: ${issue.title} - -${issue.body} - -Please triage this issue.` - - const response = await getAIResponse(prompt, systemPrompt) - - await octokit.issues.createComment({ - owner: context.owner, - repo: context.repo, - issue_number: issue.number, - body: `## 🏷️ Issue Triage - -${response} - ---- -*Generated by RooCode-Agent*`, - }) -} - -// Label an issue based on content -async function labelIssue(issue: any) { - const systemPrompt = `You are RooCode-Agent. Analyze this issue and suggest appropriate labels. -Common labels include: bug, enhancement, documentation, question, help wanted, good first issue, -frontend, backend, performance, security, testing, ui/ux. -Return only a comma-separated list of labels.` - - const prompt = `Issue #${issue.number}: ${issue.title} - -${issue.body} - -Suggest appropriate labels for this issue.` - - const response = await getAIResponse(prompt, systemPrompt) - const labels = response - .split(",") - .map((l) => l.trim()) - .filter((l) => l) - - if (labels.length > 0) { - try { - await octokit.issues.addLabels({ - owner: context.owner, - repo: context.repo, - issue_number: issue.number, - labels: labels, - }) - - await octokit.issues.createComment({ - owner: context.owner, - repo: context.repo, - issue_number: issue.number, - body: `🏷️ Added labels: ${labels.map((l) => `\`${l}\``).join(", ")}`, - }) - } catch (error) { - console.error("Error adding labels:", error) - } - } -} - -// Review a pull request -async function reviewPullRequest(pr: any) { - const systemPrompt = `You are RooCode-Agent, a code reviewer. Review this pull request and provide: -1. Summary of changes -2. Code quality assessment -3. Potential issues or bugs -4. Suggestions for improvement -5. Security considerations -6. Overall recommendation (Approve, Request Changes, or Comment)` - - // Get PR diff - const diff = await octokit.pulls.get({ - owner: context.owner, - repo: context.repo, - pull_number: pr.number, - mediaType: { format: "diff" }, - }) - - const prompt = `Pull Request #${pr.number}: ${pr.title} - -Description: -${pr.body} - -Diff: -${diff.data} - -Please review this pull request.` - - const review = await getAIResponse(prompt, systemPrompt) - - await octokit.pulls.createReview({ - owner: context.owner, - repo: context.repo, - pull_number: pr.number, - body: `## 🔍 Code Review - -${review} - ---- -*Generated by RooCode-Agent*`, - event: "COMMENT", - }) -} - -// Respond to a comment on an issue -async function respondToComment(issue: any, commentText: string) { - const systemPrompt = `You are RooCode-Agent, an AI assistant for the Roo-Code project. -Respond helpfully to the user's comment or question about this issue. -Be concise, technical, and actionable.` - - const prompt = `Issue #${issue.number}: ${issue.title} - -Issue Description: -${issue.body} - -User Comment: -${commentText} - -Please provide a helpful response.` - - const response = await getAIResponse(prompt, systemPrompt) - - await octokit.issues.createComment({ - owner: context.owner, - repo: context.repo, - issue_number: issue.number, - body: response + "\n\n---\n*Response by RooCode-Agent*", - }) -} - -// Respond to a comment on a PR -async function respondToPRComment(pr: any, commentText: string) { - const systemPrompt = `You are RooCode-Agent, an AI assistant for the Roo-Code project. -Respond helpfully to the user's comment or question about this pull request. -Be concise, technical, and actionable.` - - const prompt = `Pull Request #${pr.number}: ${pr.title} - -PR Description: -${pr.body} - -User Comment: -${commentText} - -Please provide a helpful response.` - - const response = await getAIResponse(prompt, systemPrompt) - - await octokit.issues.createComment({ - owner: context.owner, - repo: context.repo, - issue_number: pr.number, - body: response + "\n\n---\n*Response by RooCode-Agent*", - }) -} - -// Main execution -async function main() { - try { - console.log(`Processing ${context.eventName} event`) - - if (context.eventName === "issues") { - await processIssue(event.issue) - } else if (context.eventName === "issue_comment") { - await processIssue(event.issue, event.comment) - } else if (context.eventName === "pull_request") { - await processPullRequest(event.pull_request) - } else if (context.eventName === "pull_request_review_comment") { - await processPullRequest(event.pull_request, event.comment) - } else if (context.eventName === "workflow_dispatch") { - // Handle manual trigger - if (event.inputs?.issue_number) { - const issue = await octokit.issues.get({ - owner: context.owner, - repo: context.repo, - issue_number: parseInt(event.inputs.issue_number), - }) - await processIssue(issue.data) - } else if (event.inputs?.pr_number) { - const pr = await octokit.pulls.get({ - owner: context.owner, - repo: context.repo, - pull_number: parseInt(event.inputs.pr_number), - }) - await processPullRequest(pr.data) - } - } - - console.log("Event processed successfully") - } catch (error) { - console.error("Error processing event:", error) - process.exit(1) - } -} - -// Run the bot -main() diff --git a/.github/workflows/roocode-bot.yml b/.github/workflows/roocode-bot.yml deleted file mode 100644 index ef0498714e..0000000000 --- a/.github/workflows/roocode-bot.yml +++ /dev/null @@ -1,66 +0,0 @@ -name: RooCode Agent Bot - -on: - issues: - types: [opened, edited] - issue_comment: - types: [created, edited] - pull_request: - types: [opened, edited, synchronize] - pull_request_review_comment: - types: [created, edited] - workflow_dispatch: - inputs: - issue_number: - description: 'Issue number to process' - required: false - type: string - pr_number: - description: 'PR number to process' - required: false - type: string - -jobs: - process-event: - runs-on: ubuntu-latest - if: | - (github.event_name == 'issues' && contains(github.event.issue.body, '/roo')) || - (github.event_name == 'issue_comment' && contains(github.event.comment.body, '/roo')) || - (github.event_name == 'pull_request' && contains(github.event.pull_request.body, '/roo')) || - (github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '/roo')) || - github.event_name == 'workflow_dispatch' - - permissions: - contents: write - issues: write - pull-requests: write - - steps: - - name: Checkout repository - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - - name: Setup Node.js - uses: actions/setup-node@v4 - with: - node-version: '20' - - - name: Install dependencies - run: | - cd .github/scripts - npm install - - - name: Process Event - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} - ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} - OPENROUTER_API_KEY: ${{ secrets.OPENROUTER_API_KEY }} - MODEL_PROVIDER: ${{ vars.MODEL_PROVIDER || 'anthropic' }} - MODEL_NAME: ${{ vars.MODEL_NAME || 'claude-3-5-sonnet-20241022' }} - MAX_TOKENS: ${{ vars.MAX_TOKENS || '8192' }} - TEMPERATURE: ${{ vars.TEMPERATURE || '0.2' }} - run: | - cd .github/scripts - npm start \ No newline at end of file diff --git a/github-actions-workflows.md b/github-actions-workflows.md new file mode 100644 index 0000000000..34acf62485 --- /dev/null +++ b/github-actions-workflows.md @@ -0,0 +1,142 @@ +# GitHub Actions Workflows for RooCode Agent Bot + +Due to GitHub security restrictions, workflow files cannot be automatically created via GitHub Apps. Please manually add these files to your repository. + +## Required Files + +### 1. `.github/workflows/roocode-bot.yml` + +```yaml +name: RooCode Agent Bot + +on: + issues: + types: [opened, edited] + issue_comment: + types: [created, edited] + pull_request: + types: [opened, edited, synchronize] + pull_request_review_comment: + types: [created, edited] + workflow_dispatch: + inputs: + issue_number: + description: "Issue number to process" + required: false + type: string + pr_number: + description: "PR number to process" + required: false + type: string + +jobs: + process-event: + runs-on: ubuntu-latest + if: | + (github.event_name == 'issues' && contains(github.event.issue.body, '/roo')) || + (github.event_name == 'issue_comment' && contains(github.event.comment.body, '/roo')) || + (github.event_name == 'pull_request' && contains(github.event.pull_request.body, '/roo')) || + (github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '/roo')) || + github.event_name == 'workflow_dispatch' + + permissions: + contents: write + issues: write + pull-requests: write + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: "20" + + - name: Install dependencies + run: | + cd .github/scripts + npm install + + - name: Process Event + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} + ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} + OPENROUTER_API_KEY: ${{ secrets.OPENROUTER_API_KEY }} + MODEL_PROVIDER: ${{ vars.MODEL_PROVIDER || 'anthropic' }} + MODEL_NAME: ${{ vars.MODEL_NAME || 'claude-3-5-sonnet-20241022' }} + MAX_TOKENS: ${{ vars.MAX_TOKENS || '8192' }} + TEMPERATURE: ${{ vars.TEMPERATURE || '0.2' }} + run: | + cd .github/scripts + npm start +``` + +### 2. `.github/scripts/package.json` + +```json +{ + "name": "roocode-agent-scripts", + "version": "1.0.0", + "description": "RooCode Agent GitHub Actions Bot", + "type": "module", + "scripts": { + "start": "tsx roocode-agent.ts" + }, + "dependencies": { + "@octokit/rest": "^20.0.2", + "@anthropic-ai/sdk": "^0.37.0", + "openai": "^5.12.2", + "@modelcontextprotocol/sdk": "^1.12.0", + "tsx": "^4.19.3" + }, + "devDependencies": { + "@types/node": "^20.0.0" + } +} +``` + +### 3. `.github/scripts/roocode-agent.ts` + +Create this file with the full agent implementation. The complete code is available in the PR description. + +### 4. `.github/scripts/README.md` + +Documentation for the GitHub Actions bot setup and usage. + +## Setup Instructions + +1. **Add the workflow files manually** to your repository +2. **Configure Repository Secrets** (Settings → Secrets and variables → Actions): + + - `ANTHROPIC_API_KEY` or `OPENAI_API_KEY` (at least one required) + - `OPENROUTER_API_KEY` (optional) + +3. **Configure Repository Variables** (Settings → Secrets and variables → Actions → Variables): + + - `MODEL_PROVIDER`: `anthropic`, `openai`, or `openrouter` + - `MODEL_NAME`: Model identifier + - `MAX_TOKENS`: Maximum response tokens + - `TEMPERATURE`: Model temperature (0-1) + +4. **Enable GitHub Actions Permissions**: + - Go to Settings → Actions → General + - Select "Read and write permissions" + - Check "Allow GitHub Actions to create and approve pull requests" + +## Available Commands + +- `/roo plan` - Create implementation plan +- `/roo approve` - Approve plan and implement +- `/roo fix` - Direct fix implementation +- `/roo review` - Review pull request +- `/roo triage` - Triage issue +- `/roo label` - Add labels to issue +- `/roo` - General bot interaction + +## Testing + +Create an issue or PR comment with `/roo` to trigger the bot.