@@ -2,16 +2,17 @@ import Anthropic from "@anthropic-ai/sdk";
22import { readFileSync , writeFileSync , existsSync } from "fs" ;
33import { resolve , dirname } from "path" ;
44import { fileURLToPath } from "url" ;
5+ import { execSync } from "child_process" ;
56
67const __dirname = dirname ( fileURLToPath ( import . meta. url ) ) ;
78
89/**
9- * Generate Implementation - Use Claude to analyze codebase and generate implementation
10+ * Generate Implementation - Use Claude to analyze codebase and IMPLEMENT code changes
1011 *
1112 * This script uses Claude to:
1213 * 1. Analyze the existing codebase
13- * 2. Generate an implementation plan
14- * 3. Create code changes for the feature request
14+ * 2. Generate actual code changes (diffs)
15+ * 3. Apply the changes to the codebase
1516 */
1617
1718const enhancedTask = process . env . ENHANCED_TASK || process . env . TASK || "" ;
@@ -54,21 +55,22 @@ function getProjectContext() {
5455 const indexJs = readFileSync ( resolve ( repoRoot , "index.js" ) , "utf8" ) ;
5556 files . push ( {
5657 path : "index.js" ,
57- content : indexJs . substring ( 0 , 5000 ) // First 5000 chars to avoid token limits
58+ content : indexJs . substring ( 0 , 10000 ) // More context for main file
5859 } ) ;
5960 } catch ( e ) {
6061 console . warn ( "[IMPLEMENTATION] Could not read index.js" ) ;
6162 }
6263
63- // Read lib directory structure
64+ // Read lib directory files
6465 try {
6566 const libFiles = [
6667 "lib/slack.js" ,
6768 "lib/discord.js" ,
6869 "lib/voting.js" ,
6970 "lib/command-handlers.js" ,
7071 "lib/ai-handler.js" ,
71- "lib/spotify.js"
72+ "lib/spotify.js" ,
73+ "lib/add-handlers.js"
7274 ] ;
7375
7476 for ( const libFile of libFiles ) {
@@ -77,7 +79,7 @@ function getProjectContext() {
7779 const content = readFileSync ( fullPath , "utf8" ) ;
7880 files . push ( {
7981 path : libFile ,
80- content : content . substring ( 0 , 3000 ) // First 3000 chars per file
82+ content : content . substring ( 0 , 5000 ) // More context per file
8183 } ) ;
8284 }
8385 }
@@ -89,11 +91,57 @@ function getProjectContext() {
8991}
9092
9193/**
92- * Generate implementation using Claude
94+ * Apply diff to files
95+ */
96+ function applyDiff ( diff ) {
97+ const repoRoot = resolve ( __dirname , "../.." ) ;
98+ const tempPatchFile = resolve ( repoRoot , `.tmp-patch-${ issueNumber } .patch` ) ;
99+
100+ try {
101+ // Write diff to temporary patch file
102+ writeFileSync ( tempPatchFile , diff , "utf8" ) ;
103+ console . log ( `[IMPLEMENTATION] Wrote patch to ${ tempPatchFile } ` ) ;
104+
105+ // Try to apply the patch
106+ try {
107+ execSync ( `cd "${ repoRoot } " && git apply --ignore-whitespace "${ tempPatchFile } "` , {
108+ stdio : 'inherit'
109+ } ) ;
110+ console . log ( `[IMPLEMENTATION] ✅ Successfully applied patch` ) ;
111+ return true ;
112+ } catch ( applyError ) {
113+ console . warn ( `[IMPLEMENTATION] ⚠️ git apply failed, trying patch command...` ) ;
114+ try {
115+ execSync ( `cd "${ repoRoot } " && patch -p1 < "${ tempPatchFile } "` , {
116+ stdio : 'inherit'
117+ } ) ;
118+ console . log ( `[IMPLEMENTATION] ✅ Successfully applied patch with patch command` ) ;
119+ return true ;
120+ } catch ( patchError ) {
121+ console . error ( `[IMPLEMENTATION] ❌ Failed to apply patch` ) ;
122+ console . error ( `[IMPLEMENTATION] git apply error: ${ applyError . message } ` ) ;
123+ console . error ( `[IMPLEMENTATION] patch error: ${ patchError . message } ` ) ;
124+ return false ;
125+ }
126+ }
127+ } finally {
128+ // Clean up temp file
129+ try {
130+ if ( existsSync ( tempPatchFile ) ) {
131+ execSync ( `rm "${ tempPatchFile } "` ) ;
132+ }
133+ } catch ( e ) {
134+ // Ignore cleanup errors
135+ }
136+ }
137+ }
138+
139+ /**
140+ * Generate and apply implementation using Claude
93141 */
94142async function generateImplementation ( ) {
95143 try {
96- console . log ( `[IMPLEMENTATION] Generating implementation with ${ model } ...` ) ;
144+ console . log ( `[IMPLEMENTATION] Generating code implementation with ${ model } ...` ) ;
97145 console . log ( `[IMPLEMENTATION] Feature request: ${ enhancedTask } ` ) ;
98146
99147 const projectFiles = getProjectContext ( ) ;
@@ -108,7 +156,7 @@ async function generateImplementation() {
108156
109157The project is called SlackONOS and is a democratic bot where users can vote on songs to play.
110158
111- Your task is to analyze the feature request and generate a concrete implementation plan with code suggestions .
159+ Your task is to IMPLEMENT the feature request by generating actual code changes in unified diff format .
112160
113161Project context:
114162- Node.js application
@@ -118,29 +166,35 @@ Project context:
118166- Uses AI for natural language commands
119167- Supports Spotify integration
120168
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
169+ CRITICAL: You must generate a VALID unified diff that can be applied with git apply or patch command.
170+
171+ DIFF FORMAT REQUIREMENTS:
172+ 1. Start each file with "--- a/path/to/file.js" and "+++ b/path/to/file.js" (BOTH lines required)
173+ 2. NO "diff --git" line, NO "index" line with hashes
174+ 3. Include "@@ -startLine,numLines +startLine,numLines @@" hunk headers
175+ 4. Include at least 3 lines of context before and after each change
176+ 5. Use "+" prefix for additions, "-" prefix for removals, " " (space) prefix for context
177+ 6. Ensure line numbers match actual file contents
178+ 7. Output ONLY the diff - no explanations, no markdown code blocks, no text before/after
179+ 8. The diff MUST be complete and valid - every file section must have BOTH "--- a/path" AND "+++ b/path" lines
180+ 9. NEVER truncate file paths - always write complete paths
181+ 10. If creating new files, use "--- /dev/null" and "+++ b/path/to/newfile.js"
125182
126- Be specific and actionable. Focus on the actual code changes needed .`;
183+ Generate the complete, valid unified diff now .`;
127184
128185 const userPrompt = `Feature Request to Implement:
129186
130187${ enhancedTask }
131188
132189${ contextText }
133190
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
191+ Generate a valid unified diff that implements this feature. The diff must be complete and ready to apply with git apply or patch command.
138192
139- Make it actionable and ready to commit .`;
193+ Output ONLY the diff, no explanations .`;
140194
141195 const response = await anthropic . messages . create ( {
142196 model : model ,
143- max_tokens : 4096 ,
197+ max_tokens : 8192 , // Increased for larger diffs
144198 messages : [
145199 {
146200 role : "user" ,
@@ -154,23 +208,66 @@ Make it actionable and ready to commit.`;
154208 ]
155209 } ) ;
156210
157- const implementation = response . content [ 0 ] . text ;
211+ const diff = response . content [ 0 ] . text ;
158212
159- console . log ( `[IMPLEMENTATION] Generated implementation plan :` ) ;
160- console . log ( implementation ) ;
213+ console . log ( `[IMPLEMENTATION] Generated diff :` ) ;
214+ console . log ( diff ) ;
161215
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 } ` ) ;
216+ // Extract diff from potential markdown code blocks
217+ let cleanDiff = diff . trim ( ) ;
218+ if ( cleanDiff . includes ( '```' ) ) {
219+ const matches = cleanDiff . matchAll ( / ` ` ` (?: d i f f ) ? \n ( [ \s \S ] * ?) ` ` ` / g) ;
220+ const extracted = [ ] ;
221+ for ( const match of matches ) {
222+ extracted . push ( match [ 1 ] . trim ( ) ) ;
223+ }
224+ if ( extracted . length > 0 ) {
225+ cleanDiff = extracted . reduce ( ( a , b ) => a . length > b . length ? a : b ) ;
226+ }
227+ }
166228
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` ) ;
229+ // Validate diff format
230+ if ( ! cleanDiff . includes ( '--- a/' ) || ! cleanDiff . includes ( '+++ b/' ) ) {
231+ console . error ( `[IMPLEMENTATION] ❌ Generated output is not a valid diff format` ) ;
232+ console . error ( `[IMPLEMENTATION] Missing required diff markers (--- a/ or +++ b/)` ) ;
233+
234+ // Save as fallback implementation plan
235+ const outputPath = resolve ( __dirname , `../../implementation-${ issueNumber } .md` ) ;
236+ writeFileSync ( outputPath , `# Implementation Plan\n\n${ enhancedTask } \n\n## Generated Output\n\n${ diff } ` , "utf8" ) ;
237+ console . log ( `[IMPLEMENTATION] Saved as fallback plan to ${ outputPath } ` ) ;
238+ console . log ( `\nIMPLEMENTATION_FILE:${ outputPath } ` ) ;
239+ return ;
240+ }
172241
173- return implementation ;
242+ // Apply the diff
243+ const applied = applyDiff ( cleanDiff ) ;
244+
245+ if ( applied ) {
246+ console . log ( `[IMPLEMENTATION] ✅ Code changes successfully applied!` ) ;
247+
248+ // List changed files
249+ try {
250+ const changedFiles = execSync ( 'git diff --name-only' , { encoding : 'utf8' } ) . trim ( ) . split ( '\n' ) . filter ( f => f ) ;
251+ console . log ( `[IMPLEMENTATION] Changed files:` ) ;
252+ changedFiles . forEach ( f => console . log ( `[IMPLEMENTATION] - ${ f } ` ) ) ;
253+
254+ // Output marker for workflow
255+ console . log ( `\nIMPLEMENTATION_FILE:APPLIED` ) ;
256+ console . log ( `IMPLEMENTATION_CHANGED_FILES:${ changedFiles . join ( ',' ) } ` ) ;
257+ } catch ( e ) {
258+ console . warn ( `[IMPLEMENTATION] Could not list changed files: ${ e . message } ` ) ;
259+ console . log ( `\nIMPLEMENTATION_FILE:APPLIED` ) ;
260+ }
261+ } else {
262+ console . error ( `[IMPLEMENTATION] ❌ Failed to apply code changes` ) ;
263+
264+ // Save diff as fallback
265+ const outputPath = resolve ( __dirname , `../../implementation-${ issueNumber } .patch` ) ;
266+ writeFileSync ( outputPath , cleanDiff , "utf8" ) ;
267+ console . log ( `[IMPLEMENTATION] Saved diff to ${ outputPath } for manual review` ) ;
268+ console . log ( `\nIMPLEMENTATION_FILE:${ outputPath } ` ) ;
269+ process . exit ( 1 ) ;
270+ }
174271
175272 } catch ( error ) {
176273 console . error ( `[IMPLEMENTATION] Error generating implementation: ${ error . message } ` ) ;
0 commit comments