Skip to content

Commit 207c1c3

Browse files
authored
Merge pull request #229 from htilly/develop
v2.3.0: Consolidate modules, add handlers, improve tests
2 parents 69e73e2 + 005d6bd commit 207c1c3

22 files changed

Lines changed: 2080 additions & 931 deletions

.github/AI_PR_SETUP.md

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
# AI-Generated Pull Request Setup
2+
3+
This guide describes how to configure automatic PR creation with AI-generated code suggestions for feature requests.
4+
5+
## Overview
6+
7+
When an issue is created with the `enhancement` label, the workflow will:
8+
9+
1. **Enhance the issue description** - Convert to structured user story format
10+
2. **Create Confluence page** (optional) - Document requirements
11+
3. **Generate implementation with Claude AI** - Analyze codebase and create implementation plan
12+
4. **Create automatic PR** - Commit implementation plan and create PR against `develop` branch
13+
14+
## Configuration
15+
16+
### 1. GitHub Secrets
17+
18+
You need to configure the following secrets in your GitHub repository:
19+
20+
**Settings → Secrets and variables → Actions → New repository secret**
21+
22+
#### Required for AI-PR:
23+
- `ANTHROPIC_API_KEY` - Your Anthropic API key for Claude
24+
- Get from: https://console.anthropic.com/
25+
- Format: `sk-ant-api03-...`
26+
27+
#### Optional (for enhanced features):
28+
- `OPENAI_API_KEY` - For preprocessing with OpenAI
29+
- `PREPROCESSING_MODEL` - Optional, default: `gpt-4o-mini`
30+
- `CLAUDE_MODEL` - Optional, default: `claude-sonnet-4-5-20250929`
31+
32+
#### Optional (for Confluence integration):
33+
- `CONFLUENCE_URL` - Your Confluence URL (e.g. `https://your-domain.atlassian.net`)
34+
- `CONFLUENCE_EMAIL` - Your Confluence account email
35+
- `CONFLUENCE_API_TOKEN` - Confluence API token
36+
- `CONFLUENCE_SPACE_KEY` - Space key where pages should be created (default: `AICODE`)
37+
- `CONFLUENCE_PARENT_PAGE_ID` - Parent page ID (optional)
38+
39+
### 2. GitHub CLI (gh) Access
40+
41+
The workflow uses `gh` CLI to create PRs. This works automatically with `GITHUB_TOKEN` provided by GitHub Actions.
42+
43+
### 3. Repository Permissions
44+
45+
Verify that GitHub Actions has the correct permissions:
46+
47+
**Settings → Actions → General → Workflow permissions**
48+
- Select: "Read and write permissions"
49+
- Enable: "Allow GitHub Actions to create and approve pull requests"
50+
51+
## Usage
52+
53+
### Create a Feature Request
54+
55+
1. Go to **Issues → New Issue**
56+
2. Write your feature request
57+
3. Add the **`enhancement`** label
58+
4. Create the issue
59+
60+
### What Happens Automatically
61+
62+
The workflow will:
63+
64+
1. ✅ Enhance issue description with structured user story
65+
2. 📄 Create a Confluence page (if configured)
66+
3. 🤖 Use Claude AI to analyze the codebase
67+
4. 📝 Generate an implementation plan
68+
5. 🌿 Create a new branch: `feature/issue-{number}-implementation`
69+
6. 📤 Commit the file `implementation-{number}.md`
70+
7. 🔀 Create a PR against `develop` branch
71+
8. 💬 Comment on original issue with PR link
72+
73+
### PR Content
74+
75+
The PR will contain:
76+
- A markdown file with Claude's implementation plan
77+
- Analysis of existing code
78+
- Suggestions for which files need changes
79+
- Concrete code examples and instructions
80+
81+
### Next Steps After PR Creation
82+
83+
1. **Review the implementation plan** in the PR
84+
2. **Add actual code changes** based on the plan
85+
3. **Test the implementation**
86+
4. **Merge when ready**
87+
88+
## Manual Trigger
89+
90+
You can also trigger the workflow manually:
91+
92+
1. Go to **Actions → Enhance Feature Requests**
93+
2. Click **Run workflow**
94+
3. Enter issue number
95+
4. Click **Run workflow**
96+
97+
## Troubleshooting
98+
99+
### Workflow Doesn't Run
100+
101+
- Verify that issue has the `enhancement` label
102+
- Check that workflow file exists in main/master branch
103+
- Review Actions log for error messages
104+
105+
### PR Not Created
106+
107+
- Verify that `ANTHROPIC_API_KEY` is configured
108+
- Check that repository has correct permissions (see step 3 above)
109+
- Verify that `gh` CLI works in workflow log
110+
111+
### Low Quality Implementation
112+
113+
- Try using `claude-opus-4.5` instead: set secret `CLAUDE_MODEL=claude-opus-4.5-20251101`
114+
- Ensure issue description is clear and detailed
115+
- Add more context in [generate-implementation.mjs](.github/agent/generate-implementation.mjs)
116+
117+
## Cost
118+
119+
- **Anthropic Claude API**: ~$0.50-2.00 per feature request (depending on model)
120+
- **OpenAI** (optional): ~$0.01-0.10 per preprocessing
121+
- **GitHub Actions**: Free for public repos, included in private repo plans
122+
123+
## Customize the Implementation Generator
124+
125+
Edit [.github/agent/generate-implementation.mjs](.github/agent/generate-implementation.mjs) to:
126+
127+
- Add more project files for context
128+
- Modify system prompt for better output
129+
- Customize how implementation is presented
130+
131+
## Branch Strategy
132+
133+
**Important**: All PRs are automatically created against the `develop` branch. This is configured in the workflow at line 354:
134+
135+
```yaml
136+
--base develop \
137+
```
138+
139+
If you need to change the target branch, modify this line in [.github/workflows/feature-request-enhance.yml](.github/workflows/feature-request-enhance.yml).
140+
141+
## Support
142+
143+
- GitHub Issues: https://github.com/htilly/SlackONOS/issues
144+
- Claude API Docs: https://docs.anthropic.com/
Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
import Anthropic from "@anthropic-ai/sdk";
2+
import { readFileSync, writeFileSync, existsSync } from "fs";
3+
import { resolve, dirname } from "path";
4+
import { fileURLToPath } from "url";
5+
6+
const __dirname = dirname(fileURLToPath(import.meta.url));
7+
8+
/**
9+
* Generate Implementation - Use Claude to analyze codebase and generate implementation
10+
*
11+
* This script uses Claude to:
12+
* 1. Analyze the existing codebase
13+
* 2. Generate an implementation plan
14+
* 3. Create code changes for the feature request
15+
*/
16+
17+
const enhancedTask = process.env.ENHANCED_TASK || process.env.TASK || "";
18+
const issueNumber = process.env.ISSUE_NUMBER || "unknown";
19+
const anthropicApiKey = process.env.ANTHROPIC_API_KEY;
20+
const model = process.env.CLAUDE_MODEL || "claude-sonnet-4-5-20250929";
21+
22+
if (!enhancedTask) {
23+
console.error("[IMPLEMENTATION] ENHANCED_TASK or TASK environment variable not set");
24+
process.exit(1);
25+
}
26+
27+
if (!anthropicApiKey) {
28+
console.error("[IMPLEMENTATION] ANTHROPIC_API_KEY not set");
29+
process.exit(1);
30+
}
31+
32+
const anthropic = new Anthropic({ apiKey: anthropicApiKey });
33+
34+
/**
35+
* Read relevant project files to give Claude context
36+
*/
37+
function getProjectContext() {
38+
const repoRoot = resolve(__dirname, "../..");
39+
const files = [];
40+
41+
// Read package.json for dependencies
42+
try {
43+
const packageJson = readFileSync(resolve(repoRoot, "package.json"), "utf8");
44+
files.push({
45+
path: "package.json",
46+
content: packageJson
47+
});
48+
} catch (e) {
49+
console.warn("[IMPLEMENTATION] Could not read package.json");
50+
}
51+
52+
// Read main index file
53+
try {
54+
const indexJs = readFileSync(resolve(repoRoot, "index.js"), "utf8");
55+
files.push({
56+
path: "index.js",
57+
content: indexJs.substring(0, 5000) // First 5000 chars to avoid token limits
58+
});
59+
} catch (e) {
60+
console.warn("[IMPLEMENTATION] Could not read index.js");
61+
}
62+
63+
// Read lib directory structure
64+
try {
65+
const libFiles = [
66+
"lib/slack.js",
67+
"lib/discord.js",
68+
"lib/voting.js",
69+
"lib/command-handlers.js",
70+
"lib/ai-handler.js",
71+
"lib/spotify.js"
72+
];
73+
74+
for (const libFile of libFiles) {
75+
const fullPath = resolve(repoRoot, libFile);
76+
if (existsSync(fullPath)) {
77+
const content = readFileSync(fullPath, "utf8");
78+
files.push({
79+
path: libFile,
80+
content: content.substring(0, 3000) // First 3000 chars per file
81+
});
82+
}
83+
}
84+
} catch (e) {
85+
console.warn("[IMPLEMENTATION] Could not read lib files");
86+
}
87+
88+
return files;
89+
}
90+
91+
/**
92+
* Generate implementation using Claude
93+
*/
94+
async function generateImplementation() {
95+
try {
96+
console.log(`[IMPLEMENTATION] Generating implementation with ${model}...`);
97+
console.log(`[IMPLEMENTATION] Feature request: ${enhancedTask}`);
98+
99+
const projectFiles = getProjectContext();
100+
101+
// Build context from project files
102+
let contextText = "Here are relevant files from the project:\n\n";
103+
for (const file of projectFiles) {
104+
contextText += `--- ${file.path} ---\n${file.content}\n\n`;
105+
}
106+
107+
const systemPrompt = `You are an expert software developer working on a Slack/Discord bot for controlling Sonos speakers.
108+
109+
The project is called SlackONOS and is a democratic bot where users can vote on songs to play.
110+
111+
Your task is to analyze the feature request and generate a concrete implementation plan with code suggestions.
112+
113+
Project context:
114+
- Node.js application
115+
- Uses Slack Socket Mode / Events API (via @slack/socket-mode) and Discord.js
116+
- Controls Sonos speakers
117+
- Has voting system for democratic music control
118+
- Uses AI for natural language commands
119+
- Supports Spotify integration
120+
121+
Output format:
122+
1. **Implementation Plan** - Brief overview of what needs to be changed
123+
2. **Files to Modify/Create** - List specific files
124+
3. **Code Changes** - Provide actual code snippets or full file contents
125+
126+
Be specific and actionable. Focus on the actual code changes needed.`;
127+
128+
const userPrompt = `Feature Request to Implement:
129+
130+
${enhancedTask}
131+
132+
${contextText}
133+
134+
Please provide:
135+
1. A brief implementation plan
136+
2. List of files to modify or create
137+
3. Actual code changes with clear instructions
138+
139+
Make it actionable and ready to commit.`;
140+
141+
const response = await anthropic.messages.create({
142+
model: model,
143+
max_tokens: 4096,
144+
messages: [
145+
{
146+
role: "user",
147+
content: [
148+
{
149+
type: "text",
150+
text: `${systemPrompt}\n\n${userPrompt}`
151+
}
152+
]
153+
}
154+
]
155+
});
156+
157+
const implementation = response.content[0].text;
158+
159+
console.log(`[IMPLEMENTATION] Generated implementation plan:`);
160+
console.log(implementation);
161+
162+
// Save implementation to file for the workflow to use
163+
const outputPath = resolve(__dirname, `../../implementation-${issueNumber}.md`);
164+
writeFileSync(outputPath, implementation, "utf8");
165+
console.log(`[IMPLEMENTATION] Saved to ${outputPath}`);
166+
167+
// Output markers for workflow parsing
168+
console.log(`\nIMPLEMENTATION_FILE:${outputPath}`);
169+
console.log(`IMPLEMENTATION_START`);
170+
console.log(implementation);
171+
console.log(`IMPLEMENTATION_END`);
172+
173+
return implementation;
174+
175+
} catch (error) {
176+
console.error(`[IMPLEMENTATION] Error generating implementation: ${error.message}`);
177+
if (error.response) {
178+
console.error(`[IMPLEMENTATION] API Error: ${JSON.stringify(error.response.data)}`);
179+
}
180+
process.exit(1);
181+
}
182+
}
183+
184+
generateImplementation();

0 commit comments

Comments
 (0)