Skip to content

Commit 5a52a51

Browse files
committed
Filter CI logs and add Ctrl+C support
- Add filterCILogs() to extract only relevant error information - Show concise error summary instead of dumping raw logs - Truncate logs to 2000 chars to avoid context warnings - Simplify prompts to reduce token usage - Add SIGINT handlers to properly handle Ctrl+C - Add debug output showing Claude command flags
1 parent 5327f2e commit 5a52a51

File tree

1 file changed

+132
-42
lines changed

1 file changed

+132
-42
lines changed

scripts/claude.mjs

Lines changed: 132 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -926,6 +926,66 @@ async function buildEnhancedPrompt(template, basePrompt, options = {}) {
926926
return enhancedPrompt
927927
}
928928

929+
/**
930+
* Filter CI logs to extract only relevant failure information
931+
* Removes runner setup noise and focuses on actual errors
932+
*/
933+
function filterCILogs(rawLogs) {
934+
const lines = rawLogs.split('\n')
935+
const relevantLines = []
936+
let inErrorSection = false
937+
938+
for (const line of lines) {
939+
// Skip runner metadata and setup
940+
if (
941+
line.includes('Current runner version:') ||
942+
line.includes('Runner Image') ||
943+
line.includes('Operating System') ||
944+
line.includes('GITHUB_TOKEN') ||
945+
line.includes('Prepare workflow') ||
946+
line.includes('Prepare all required') ||
947+
line.includes('##[group]') ||
948+
line.includes('##[endgroup]') ||
949+
line.includes('Post job cleanup') ||
950+
line.includes('git config') ||
951+
line.includes('git submodule') ||
952+
line.includes('Cleaning up orphan') ||
953+
line.includes('secret source:') ||
954+
line.includes('[command]/usr/bin/git')
955+
) {
956+
continue
957+
}
958+
959+
// Detect error sections
960+
if (
961+
line.includes('##[error]') ||
962+
line.includes('Error:') ||
963+
line.includes('error TS') ||
964+
line.includes('FAIL') ||
965+
line.includes('✗') ||
966+
line.includes('❌') ||
967+
line.includes('failed') ||
968+
line.includes('ELIFECYCLE')
969+
) {
970+
inErrorSection = true
971+
relevantLines.push(line)
972+
} else if (inErrorSection && line.trim() !== '') {
973+
relevantLines.push(line)
974+
// Keep context for 5 lines after error
975+
if (relevantLines.length > 100) {
976+
inErrorSection = false
977+
}
978+
}
979+
}
980+
981+
// If no errors found, return last 50 lines (might contain useful context)
982+
if (relevantLines.length === 0) {
983+
return lines.slice(-50).join('\n')
984+
}
985+
986+
return relevantLines.join('\n')
987+
}
988+
929989
/**
930990
* Prepare Claude command arguments for Claude Code.
931991
* Claude Code uses natural language prompts, not the same flags.
@@ -3249,9 +3309,23 @@ Let's work through this together to get CI passing.`
32493309
// Add newline after progress indicator before next output
32503310
console.log('')
32513311

3312+
// Filter and show summary of logs
3313+
const rawLogs = logsResult.stdout || 'No logs available'
3314+
const filteredLogs = filterCILogs(rawLogs)
3315+
3316+
const logLines = filteredLogs.split('\n').slice(0, 10)
3317+
log.substep('Error summary:')
3318+
for (const line of logLines) {
3319+
if (line.trim()) {
3320+
log.substep(` ${line.trim().substring(0, 100)}`)
3321+
}
3322+
}
3323+
if (filteredLogs.split('\n').length > 10) {
3324+
log.substep(` ... (${filteredLogs.split('\n').length - 10} more lines)`)
3325+
}
3326+
32523327
// Check if we've seen this CI error before
3253-
const ciErrorOutput = logsResult.stdout || 'No logs available'
3254-
const ciErrorHash = hashError(ciErrorOutput)
3328+
const ciErrorHash = hashError(filteredLogs)
32553329

32563330
if (ciErrorHistory.has(lastRunId)) {
32573331
log.error(`Already attempted fix for run ${lastRunId}`)
@@ -3274,29 +3348,18 @@ Let's work through this together to get CI passing.`
32743348

32753349
// Analyze and fix with Claude
32763350
log.progress('Analyzing CI failure with Claude')
3277-
const fixPrompt = `You are automatically fixing CI failures. The CI workflow failed for commit ${currentSha} in ${owner}/${repo}.
32783351

3279-
Failure logs:
3280-
${logsResult.stdout || 'No logs available'}
3352+
// Keep logs under 2000 chars to avoid context issues
3353+
const truncatedLogs = filteredLogs.length > 2000
3354+
? filteredLogs.substring(0, 2000) + '\n... (truncated)'
3355+
: filteredLogs
32813356

3282-
Your task:
3283-
1. Analyze these CI logs
3284-
2. Identify the root cause of failures
3285-
3. Apply fixes directly to resolve the issues
3357+
const fixPrompt = `Fix CI failures for commit ${currentSha.substring(0, 7)} in ${owner}/${repo}.
32863358
3287-
Focus on:
3288-
- Test failures: Update snapshots, fix test logic, or correct test data
3289-
- Lint errors: Fix code style and formatting issues
3290-
- Type checking: Fix type errors and missing type annotations
3291-
- Build problems: Fix import errors, missing pinned dependencies, or syntax issues
3359+
Error logs:
3360+
${truncatedLogs}
32923361
3293-
IMPORTANT:
3294-
- Be direct and apply fixes immediately
3295-
- Don't ask for clarification or permission
3296-
- Make all necessary file changes to fix the CI
3297-
- If multiple issues exist, fix them all
3298-
3299-
Fix all CI failures now by making the necessary changes.`
3362+
Fix all issues by making necessary file changes. Be direct, don't ask questions.`
33003363

33013364
// Run Claude non-interactively to apply fixes
33023365
log.substep('Applying CI fixes...')
@@ -3355,11 +3418,20 @@ Fix all CI failures now by making the necessary changes.`
33553418
shell: true,
33563419
})
33573420

3421+
// Handle Ctrl+C gracefully
3422+
const sigintHandler = () => {
3423+
child.kill('SIGINT')
3424+
resolve(130)
3425+
}
3426+
process.on('SIGINT', sigintHandler)
3427+
33583428
child.on('exit', code => {
3429+
process.off('SIGINT', sigintHandler)
33593430
resolve(code || 0)
33603431
})
33613432

33623433
child.on('error', () => {
3434+
process.off('SIGINT', sigintHandler)
33633435
resolve(1)
33643436
})
33653437
})
@@ -3505,34 +3577,38 @@ Fix all CI failures now by making the necessary changes.`
35053577
)
35063578
console.log('')
35073579

3580+
// Filter logs to extract relevant errors
3581+
const rawLogs = logsResult.stdout || 'No logs available'
3582+
const filteredLogs = filterCILogs(rawLogs)
3583+
3584+
// Show summary to user (not full logs)
3585+
const logLines = filteredLogs.split('\n').slice(0, 10)
3586+
log.substep('Error summary:')
3587+
for (const line of logLines) {
3588+
if (line.trim()) {
3589+
log.substep(` ${line.trim().substring(0, 100)}`)
3590+
}
3591+
}
3592+
if (filteredLogs.split('\n').length > 10) {
3593+
log.substep(` ... (${filteredLogs.split('\n').length - 10} more lines)`)
3594+
}
3595+
35083596
// Analyze and fix with Claude
35093597
log.progress(`Analyzing failure in ${job.name}`)
3510-
const fixPrompt = `You are automatically fixing CI failures. The job "${job.name}" failed in workflow run ${lastRunId} for commit ${currentSha} in ${owner}/${repo}.
35113598

3512-
Job: ${job.name}
3513-
Status: ${job.conclusion}
3599+
// Keep logs under 2000 chars to avoid context issues
3600+
const truncatedLogs = filteredLogs.length > 2000
3601+
? filteredLogs.substring(0, 2000) + '\n... (truncated)'
3602+
: filteredLogs
35143603

3515-
Failure logs:
3516-
${logsResult.stdout || 'No logs available'}
3604+
const fixPrompt = `Fix CI failure in "${job.name}" (run ${lastRunId}, commit ${currentSha.substring(0, 7)}).
35173605
3518-
Your task:
3519-
1. Analyze these CI logs for the "${job.name}" job
3520-
2. Identify the root cause of the failure
3521-
3. Apply fixes directly to resolve the issue
3522-
3523-
Focus on:
3524-
- Test failures: Update snapshots, fix test logic, or correct test data
3525-
- Lint errors: Fix code style and formatting issues
3526-
- Type checking: Fix type errors and missing type annotations
3527-
- Build problems: Fix import errors, missing pinned dependencies, or syntax issues
3606+
Status: ${job.conclusion}
35283607
3529-
IMPORTANT:
3530-
- Be direct and apply fixes immediately
3531-
- Don't ask for clarification or permission
3532-
- Make all necessary file changes to fix this specific failure
3533-
- Focus ONLY on fixing the "${job.name}" job
3608+
Error logs:
3609+
${truncatedLogs}
35343610
3535-
Fix the failure now by making the necessary changes.`
3611+
Fix the issue by making necessary file changes. Be direct, don't ask questions.`
35363612

35373613
// Run Claude non-interactively to apply fixes
35383614
log.substep(`Applying fix for ${job.name}...`)
@@ -3563,6 +3639,11 @@ Fix the failure now by making the necessary changes.`
35633639
? `${claudeCmd} ${claudeArgs}`
35643640
: claudeCmd
35653641

3642+
// Debug: Show command being run
3643+
if (claudeArgs) {
3644+
log.substep(`Running: claude ${claudeArgs}`)
3645+
}
3646+
35663647
// Use script command to create pseudo-TTY for Ink compatibility
35673648
// Platform-specific script command syntax
35683649
let scriptCmd
@@ -3587,11 +3668,20 @@ Fix the failure now by making the necessary changes.`
35873668
shell: true,
35883669
})
35893670

3671+
// Handle Ctrl+C gracefully
3672+
const sigintHandler = () => {
3673+
child.kill('SIGINT')
3674+
resolve(130)
3675+
}
3676+
process.on('SIGINT', sigintHandler)
3677+
35903678
child.on('exit', code => {
3679+
process.off('SIGINT', sigintHandler)
35913680
resolve(code || 0)
35923681
})
35933682

35943683
child.on('error', () => {
3684+
process.off('SIGINT', sigintHandler)
35953685
resolve(1)
35963686
})
35973687
})

0 commit comments

Comments
 (0)