11import { execSync } from 'child_process'
22import fs from 'fs'
3- import os from 'os'
43import path from 'path'
54
5+ import { generatePrompt } from './llm'
6+
67export interface CommitTask {
78 sha : string
89 parentSha : string
@@ -14,6 +15,55 @@ export interface CommitTask {
1415
1516const MAX_DIFF_CHARS = 200_000
1617
18+ /**
19+ * Commit message patterns that indicate trivial/automated commits not worth
20+ * running agents on. Saves ~10 agent+judge invocations per skipped commit.
21+ */
22+ const TRIVIAL_COMMIT_PATTERNS = [
23+ / ^ b u m p \b .* \b v e r s i o n \b / i,
24+ / ^ v ? \d + \. \d + \. \d + $ / , // version-only messages like "1.0.635"
25+ / ^ r e l e a s e \s + v ? \d + / i,
26+ / ^ c h o r e \( r e l e a s e \) / i,
27+ / ^ u p d a t e \s + ( c h a n g e | c h a n g e l o g ) / i,
28+ / ^ m e r g e \s + ( b r a n c h | p u l l r e q u e s t ) / i,
29+ ]
30+
31+ /**
32+ * Returns true if a commit is trivial and should be skipped.
33+ * Checks commit message patterns and whether only package.json version fields changed.
34+ */
35+ function isTrivialCommit (
36+ message : string ,
37+ filesChanged : string [ ] ,
38+ diff : string ,
39+ ) : boolean {
40+ const firstLine = message . split ( '\n' ) [ 0 ] . trim ( )
41+
42+ // Check message patterns
43+ if ( TRIVIAL_COMMIT_PATTERNS . some ( ( p ) => p . test ( firstLine ) ) ) return true
44+
45+ // Single package.json change that only touches "version" field
46+ if (
47+ filesChanged . length === 1 &&
48+ filesChanged [ 0 ] . endsWith ( 'package.json' ) &&
49+ diff . length < 1000
50+ ) {
51+ const addedLines = diff
52+ . split ( '\n' )
53+ . filter ( ( l ) => l . startsWith ( '+' ) && ! l . startsWith ( '+++' ) )
54+ const removedLines = diff
55+ . split ( '\n' )
56+ . filter ( ( l ) => l . startsWith ( '-' ) && ! l . startsWith ( '---' ) )
57+ const allVersionChanges =
58+ [ ...addedLines , ...removedLines ] . every ( ( l ) =>
59+ / ^ \s * [ + - ] \s * " v e r s i o n " / . test ( l ) ,
60+ )
61+ if ( allVersionChanges ) return true
62+ }
63+
64+ return false
65+ }
66+
1767/**
1868 * Files that add noise to diffs without useful signal.
1969 * Lockfiles are huge and auto-generated — agents shouldn't replicate them.
@@ -231,31 +281,14 @@ ${filesSection}## Diff
231281${ diff }
232282\`\`\``
233283
234- const tmpDir = fs . mkdtempSync ( path . join ( os . tmpdir ( ) , 'evalbuff-promptgen-' ) )
235- const promptFile = path . join ( tmpDir , 'PROMPT_GEN.md' )
236-
237284 try {
238- fs . writeFileSync ( promptFile , `${ PROMPT_GEN_SYSTEM } \n\n---\n\n${ userPrompt } ` )
239-
240- // IMPORTANT: Run in tmpDir to avoid Claude reading the repo's CLAUDE.md/AGENTS.md,
241- // which can confuse prompt generation (e.g., generating prompts about evalbuff itself).
242- const output = execSync (
243- `claude --dangerously-skip-permissions -p "Read ${ promptFile } and follow all instructions. Respond with ONLY the task prompt text."` ,
244- {
245- cwd : tmpDir ,
246- encoding : 'utf-8' ,
247- timeout : 2 * 60 * 1000 ,
248- stdio : [ 'ignore' , 'pipe' , 'pipe' ] ,
249- maxBuffer : 10 * 1024 * 1024 ,
250- } ,
251- ) . trim ( )
252-
285+ // Use API directly — faster than spawning Claude CLI (~3s vs ~15s)
286+ // and avoids CLAUDE.md/AGENTS.md context pollution
287+ const output = await generatePrompt ( PROMPT_GEN_SYSTEM , userPrompt )
253288 return output || message
254289 } catch {
255290 // Fallback to the commit message itself
256291 return message
257- } finally {
258- fs . rmSync ( tmpDir , { recursive : true , force : true } )
259292 }
260293}
261294
@@ -270,6 +303,12 @@ export async function buildCommitTask(
270303 const info = getCommitInfo ( repoPath , sha )
271304 if ( ! info ) return null
272305
306+ // Skip trivial/automated commits (version bumps, releases, etc.)
307+ if ( isTrivialCommit ( info . message , info . filesChanged , info . diff ) ) {
308+ console . log ( `Skipping ${ sha . slice ( 0 , 8 ) } : trivial commit (${ info . message . split ( '\n' ) [ 0 ] . slice ( 0 , 50 ) } )` )
309+ return null
310+ }
311+
273312 // Skip commits with diffs that exceed our limit
274313 if ( info . diff . length > MAX_DIFF_CHARS ) {
275314 console . log ( `Skipping ${ sha . slice ( 0 , 8 ) } : diff too large (${ info . diff . length } chars)` )
0 commit comments