@@ -132,14 +132,29 @@ async function checkClaude() {
132132 * Prepare Claude command arguments.
133133 * Adds --dangerously-skip-permissions by default (Let's get dangerous!)
134134 * unless --no-darkwing flag is used.
135+ * Adds model selection based on --pinky (default) or --the-brain (expensive).
135136 */
136137function prepareClaudeArgs ( args = [ ] , options = { } ) {
137138 const opts = { __proto__ : null , ...options }
139+ const claudeArgs = [ ...args ]
140+
138141 // "Let's get dangerous!" - Darkwing Duck.
139142 if ( ! opts [ 'no-darkwing' ] ) {
140- return [ '--dangerously-skip-permissions' , ...args ]
143+ claudeArgs . unshift ( '--dangerously-skip-permissions' )
144+ }
145+
146+ // "Gee, Brain, what do you want to do tonight?" - Pinky
147+ // "The same thing we do every night, Pinky - try to take over the world!" - The Brain
148+ if ( opts [ 'the-brain' ] ) {
149+ // Use the expensive, powerful model (Claude 3 Opus)
150+ claudeArgs . push ( '--model' , 'claude-3-opus-20240229' )
151+ } else if ( opts . pinky ) {
152+ // Explicitly use the default model (Claude 3.5 Sonnet)
153+ claudeArgs . push ( '--model' , 'claude-3-5-sonnet-20241022' )
141154 }
142- return args
155+ // If neither flag is set, let claude-console use its default
156+
157+ return claudeArgs
143158}
144159
145160/**
@@ -158,25 +173,64 @@ function shouldRunParallel(options = {}) {
158173
159174/**
160175 * Run tasks in parallel with progress tracking.
176+ * NOTE: When running Claude agents in parallel, they must use stdio: 'pipe' to avoid
177+ * conflicting interactive prompts. If agents need user interaction, they would queue
178+ * and block each other. Use --seq flag for sequential execution with full interactivity.
161179 */
162- async function runParallel ( tasks , description = 'tasks' ) {
180+ async function runParallel ( tasks , description = 'tasks' , taskNames = [ ] ) {
163181 log . info ( `Running ${ tasks . length } ${ description } in parallel...` )
164182
165- const results = await Promise . allSettled ( tasks )
183+ const startTime = Date . now ( )
184+ let completed = 0
185+
186+ // Add progress tracking to each task
187+ const trackedTasks = tasks . map ( ( task , index ) => {
188+ const name = taskNames [ index ] || `Task ${ index + 1 } `
189+ const taskStartTime = Date . now ( )
190+
191+ return task . then (
192+ result => {
193+ completed ++
194+ const elapsed = Math . round ( ( Date . now ( ) - taskStartTime ) / 1000 )
195+ log . done ( `[${ name } ] Completed (${ elapsed } s) - ${ completed } /${ tasks . length } ` )
196+ return result
197+ } ,
198+ error => {
199+ completed ++
200+ const elapsed = Math . round ( ( Date . now ( ) - taskStartTime ) / 1000 )
201+ log . failed ( `[${ name } ] Failed (${ elapsed } s) - ${ completed } /${ tasks . length } ` )
202+ throw error
203+ }
204+ )
205+ } )
206+
207+ // Progress indicator
208+ const progressInterval = setInterval ( ( ) => {
209+ const elapsed = Math . round ( ( Date . now ( ) - startTime ) / 1000 )
210+ const pending = tasks . length - completed
211+ if ( pending > 0 ) {
212+ log . substep ( `Progress: ${ completed } /${ tasks . length } complete, ${ pending } running (${ elapsed } s elapsed)` )
213+ }
214+ } , 15000 ) // Update every 15 seconds
215+
216+ const results = await Promise . allSettled ( trackedTasks )
217+ clearInterval ( progressInterval )
166218
219+ const totalElapsed = Math . round ( ( Date . now ( ) - startTime ) / 1000 )
167220 const succeeded = results . filter ( r => r . status === 'fulfilled' ) . length
168221 const failed = results . filter ( r => r . status === 'rejected' ) . length
169222
170223 if ( failed > 0 ) {
171- log . warn ( `Completed: ${ succeeded } succeeded, ${ failed } failed` )
172- // Log errors
224+ log . warn ( `Completed in ${ totalElapsed } s : ${ succeeded } succeeded, ${ failed } failed` )
225+ // Log errors with task names
173226 results . forEach ( ( result , index ) => {
174227 if ( result . status === 'rejected' ) {
175- log . error ( `Task ${ index + 1 } failed: ${ result . reason } ` )
228+ const name = taskNames [ index ] || `Task ${ index + 1 } `
229+ log . error ( `[${ name } ] failed: ${ result . reason } ` )
176230 }
177231 } )
178232 } else {
179- log . success ( `All ${ succeeded } ${ description } completed successfully` )
233+ log . success ( `All ${ succeeded } ${ description } completed successfully in ${ totalElapsed } s ` )
180234 }
181235
182236 return results
@@ -404,7 +458,8 @@ async function syncClaudeMd(claudeCmd, options = {}) {
404458 . catch ( error => ( { project : project . name , success : false , error } ) )
405459 )
406460
407- const results = await runParallel ( tasks , 'CLAUDE.md updates' )
461+ const taskNames = projects . map ( p => path . basename ( p ) )
462+ const results = await runParallel ( tasks , 'CLAUDE.md updates' , taskNames )
408463
409464 // Check for failures
410465 results . forEach ( result => {
@@ -430,7 +485,8 @@ async function syncClaudeMd(claudeCmd, options = {}) {
430485 if ( shouldRunParallel ( opts ) && projects . length > 1 ) {
431486 // Run commits in parallel
432487 const tasks = projects . map ( project => commitChanges ( project ) )
433- await runParallel ( tasks , 'commits' )
488+ const taskNames = projects . map ( p => path . basename ( p ) )
489+ await runParallel ( tasks , 'commits' , taskNames )
434490 } else {
435491 // Run sequentially
436492 for ( const project of projects ) {
@@ -743,7 +799,8 @@ async function runSecurityScan(claudeCmd, options = {}) {
743799 . catch ( error => ( { project : project . name , issues : null , error } ) )
744800 )
745801
746- const results = await runParallel ( tasks , 'security scans' )
802+ const taskNames = projects . map ( p => p . name )
803+ const results = await runParallel ( tasks , 'security scans' , taskNames )
747804
748805 // Collect results
749806 results . forEach ( result => {
@@ -779,6 +836,9 @@ async function runSecurityScan(claudeCmd, options = {}) {
779836
780837/**
781838 * Run Claude-assisted commits across Socket projects.
839+ * IMPORTANT: When running in parallel mode (default), Claude agents run silently (stdio: 'pipe').
840+ * Interactive prompts would conflict if multiple agents needed user input simultaneously.
841+ * Use --seq flag if you need interactive debugging across multiple repos.
782842 */
783843async function runClaudeCommit ( claudeCmd , options = { } ) {
784844 const opts = { __proto__ : null , ...options }
@@ -1519,6 +1579,8 @@ Be specific and actionable.`
15191579
15201580/**
15211581 * Run all checks, push, and monitor CI until green.
1582+ * NOTE: This operates on the current repo only. For multi-repo CI, run --green in each repo.
1583+ * Multi-repo parallel execution would conflict with interactive prompts if fixes fail.
15221584 */
15231585async function runGreen ( claudeCmd , options = { } ) {
15241586 const opts = { __proto__ : null , ...options }
@@ -1529,19 +1591,20 @@ async function runGreen(claudeCmd, options = {}) {
15291591 printHeader ( 'Green CI Pipeline' )
15301592
15311593 // Step 1: Run local checks
1532- log . step ( 'Running local checks' )
1594+ const repoName = path . basename ( rootPath )
1595+ log . step ( `Running local checks in ${ colors . cyan ( repoName ) } ` )
15331596 const localChecks = [
15341597 { name : 'Install dependencies' , cmd : 'pnpm' , args : [ 'install' ] } ,
15351598 { name : 'Fix code style' , cmd : 'pnpm' , args : [ 'run' , 'fix' ] } ,
15361599 { name : 'Run checks' , cmd : 'pnpm' , args : [ 'run' , 'check' ] } ,
1537- { name : 'Run coverage' , cmd : 'pnpm' , args : [ 'run' , 'coverage ' ] } ,
1600+ { name : 'Run coverage' , cmd : 'pnpm' , args : [ 'run' , 'cover ' ] } ,
15381601 { name : 'Run tests' , cmd : 'pnpm' , args : [ 'run' , 'test' , '--' , '--update' ] }
15391602 ]
15401603
15411604 let autoFixAttempts = 0
15421605
15431606 for ( const check of localChecks ) {
1544- log . progress ( check . name )
1607+ log . progress ( `[ ${ repoName } ] ${ check . name } ` )
15451608
15461609 if ( isDryRun ) {
15471610 log . done ( `[DRY RUN] Would run: ${ check . cmd } ${ check . args . join ( ' ' ) } ` )
@@ -1563,7 +1626,7 @@ async function runGreen(claudeCmd, options = {}) {
15631626
15641627 if ( isAutoMode ) {
15651628 // Attempt automatic fix
1566- log . progress ( `Attempting auto -fix with Claude ( attempt ${ autoFixAttempts } /${ MAX_AUTO_FIX_ATTEMPTS } ) ` )
1629+ log . progress ( `[ ${ repoName } ] Auto -fix attempt ${ autoFixAttempts } /${ MAX_AUTO_FIX_ATTEMPTS } ` )
15671630
15681631 const fixPrompt = `You are fixing a CI/build issue automatically. The command "${ check . cmd } ${ check . args . join ( ' ' ) } " failed in the ${ path . basename ( rootPath ) } project.
15691632
@@ -1582,19 +1645,46 @@ IMPORTANT:
15821645- If it's a type error, fix the code
15831646- If it's a lint error, fix the formatting
15841647- If tests are failing, update snapshots or fix the test
1648+ - If a script is missing, check if there's a similar script name (e.g., 'cover' vs 'coverage')
15851649
15861650Fix this issue now by making the necessary changes.`
15871651
1588- // Run Claude non-interactively to get the fix
1589- log . substep ( 'Analyzing error and applying fixes...' )
1590- await runCommand ( claudeCmd , prepareClaudeArgs ( [ ] , opts ) , {
1591- input : fixPrompt ,
1652+ // Run Claude non-interactively with timeout and progress
1653+ const startTime = Date . now ( )
1654+ const timeout = 120000 // 2 minute timeout
1655+ log . substep ( `[${ repoName } ] Analyzing error...` )
1656+
1657+ const claudeProcess = spawn ( claudeCmd , prepareClaudeArgs ( [ ] , opts ) , {
15921658 cwd : rootPath ,
1593- stdio : 'pipe' // Don't inherit stdio - run silently
1659+ stdio : [ 'pipe' , 'pipe' , 'pipe' ]
1660+ } )
1661+
1662+ claudeProcess . stdin . write ( fixPrompt )
1663+ claudeProcess . stdin . end ( )
1664+
1665+ // Monitor progress with timeout
1666+ let progressInterval = setInterval ( ( ) => {
1667+ const elapsed = Date . now ( ) - startTime
1668+ if ( elapsed > timeout ) {
1669+ log . warn ( `[${ repoName } ] Claude fix timed out after ${ Math . round ( elapsed / 1000 ) } s` )
1670+ claudeProcess . kill ( )
1671+ clearInterval ( progressInterval )
1672+ } else {
1673+ log . substep ( `[${ repoName } ] Claude working... (${ Math . round ( elapsed / 1000 ) } s)` )
1674+ }
1675+ } , 10000 ) // Update every 10 seconds
1676+
1677+ await new Promise ( ( resolve ) => {
1678+ claudeProcess . on ( 'close' , ( ) => {
1679+ clearInterval ( progressInterval )
1680+ const elapsed = Date . now ( ) - startTime
1681+ log . done ( `[${ repoName } ] Claude fix completed in ${ Math . round ( elapsed / 1000 ) } s` )
1682+ resolve ( )
1683+ } )
15941684 } )
15951685
1596- // Give Claude's changes a moment to complete
1597- await new Promise ( resolve => setTimeout ( resolve , 2000 ) )
1686+ // Give file system a moment to sync
1687+ await new Promise ( resolve => setTimeout ( resolve , 1000 ) )
15981688
15991689 // Retry the check
16001690 log . progress ( `Retrying ${ check . name } ` )
@@ -2026,6 +2116,14 @@ async function main() {
20262116 type : 'string' ,
20272117 default : '10' ,
20282118 } ,
2119+ pinky : {
2120+ type : 'boolean' ,
2121+ default : false ,
2122+ } ,
2123+ 'the-brain' : {
2124+ type : 'boolean' ,
2125+ default : false ,
2126+ } ,
20292127 } ,
20302128 allowPositionals : true ,
20312129 strict : false ,
@@ -2053,13 +2151,17 @@ async function main() {
20532151 console . log ( ' --no-darkwing Disable "Let\'s get dangerous!" mode' )
20542152 console . log ( ' --max-retries N Max CI fix attempts (--green, default: 3)' )
20552153 console . log ( ' --max-auto-fixes N Max auto-fix attempts before interactive (--green, default: 10)' )
2154+ console . log ( ' --pinky Use default model (Claude 3.5 Sonnet)' )
2155+ console . log ( ' --the-brain Use expensive model (Claude 3 Opus) - "Try to take over the world!"' )
20562156 console . log ( '\nExamples:' )
20572157 console . log ( ' pnpm claude --review # Review staged changes' )
20582158 console . log ( ' pnpm claude --fix # Scan for issues' )
20592159 console . log ( ' pnpm claude --green # Ensure CI passes' )
20602160 console . log ( ' pnpm claude --green --dry-run # Test green without real CI' )
20612161 console . log ( ' pnpm claude --green --max-retries 5 # More CI retry attempts' )
20622162 console . log ( ' pnpm claude --green --max-auto-fixes 3 # Fewer auto-fix attempts' )
2163+ console . log ( ' pnpm claude --fix --the-brain # Deep analysis with powerful model' )
2164+ console . log ( ' pnpm claude --refactor --pinky # Quick refactor with default model' )
20632165 console . log ( ' pnpm claude --test lib/utils.js # Generate tests for a file' )
20642166 console . log ( ' pnpm claude --explain path.join # Explain a concept' )
20652167 console . log ( ' pnpm claude --refactor src/index.js # Suggest refactoring' )
0 commit comments