2026-03-13 17:40:39 -07:00
/**
2026-03-13 19:03:30 -07:00
* Universal Offload Worker (Remote)
2026-03-13 18:40:14 -07:00
*
2026-03-13 19:03:30 -07:00
* Handles worktree provisioning and parallel task execution based on 'playbooks'.
2026-03-13 17:40:39 -07:00
*/
import { spawn , spawnSync } from 'child_process' ;
import path from 'path' ;
import fs from 'fs' ;
const prNumber = process . argv [ 2 ] ;
const branchName = process . argv [ 3 ] ;
2026-03-13 18:40:14 -07:00
const policyPath = process . argv [ 4 ] ;
2026-03-13 19:03:30 -07:00
const action = process . argv [ 5 ] || 'review' ;
2026-03-13 17:40:39 -07:00
2026-03-13 19:03:30 -07:00
async function main() {
2026-03-13 18:40:14 -07:00
if ( ! prNumber || ! branchName || ! policyPath ) {
2026-03-13 19:03:30 -07:00
console . error ( 'Usage: tsx worker.ts <PR_NUMBER> <BRANCH_NAME> <POLICY_PATH> [action]' ) ;
2026-03-13 18:45:06 -07:00
return 1 ;
2026-03-13 17:40:39 -07:00
}
2026-03-13 18:40:14 -07:00
const workDir = process . cwd ( ) ; // This is remoteWorkDir
2026-03-13 17:40:39 -07:00
const targetDir = path . join ( workDir , branchName ) ;
2026-03-13 19:03:30 -07:00
// 1. Provision PR Directory
2026-03-13 17:40:39 -07:00
if ( ! fs . existsSync ( targetDir ) ) {
console . log ( ` 🌿 Provisioning PR # ${ prNumber } into ${ branchName } ... ` ) ;
const cloneCmd = ` git clone --filter=blob:none https://github.com/google-gemini/gemini-cli.git ${ targetDir } ` ;
spawnSync ( cloneCmd , { stdio : 'inherit' , shell : true } ) ;
process . chdir ( targetDir ) ;
spawnSync ( 'gh' , [ 'pr' , 'checkout' , prNumber ] , { stdio : 'inherit' } ) ;
} else {
process . chdir ( targetDir ) ;
}
2026-03-13 19:03:30 -07:00
const logDir = path . join ( targetDir , ` .gemini/logs/offload- ${ prNumber } ` ) ;
2026-03-13 17:40:39 -07:00
fs . mkdirSync ( logDir , { recursive : true } ) ;
2026-03-13 18:40:14 -07:00
const geminiBin = path . join ( workDir , 'node_modules/.bin/gemini' ) ;
2026-03-13 17:40:39 -07:00
2026-03-13 19:03:30 -07:00
// 2. Define Playbooks
let tasks : any [ ] = [ ] ;
if ( action === 'review' ) {
tasks = [
{ id : 'build' , name : 'Fast Build' , cmd : ` cd ${ targetDir } && npm ci && npm run build ` } ,
{ id : 'ci' , name : 'CI Checks' , cmd : ` gh pr checks ${ prNumber } ` } ,
{ id : 'review' , name : 'Gemini Analysis' , cmd : ` ${ geminiBin } --policy ${ policyPath } --cwd ${ targetDir } -p "/review-frontend ${ prNumber } " ` } ,
{ id : 'verify' , name : 'Behavioral Proof' , cmd : ` ${ geminiBin } --policy ${ policyPath } --cwd ${ targetDir } -p "Analyze the code in ${ targetDir } and exercise it to prove it works." ` , dep : 'build' }
] ;
} else if ( action === 'fix' ) {
tasks = [
{ id : 'build' , name : 'Fast Build' , cmd : ` cd ${ targetDir } && npm ci && npm run build ` } ,
{ id : 'failures' , name : 'Find Failures' , cmd : ` gh run view --log-failed ` } ,
{ id : 'fix' , name : 'Iterative Fix' , cmd : ` ${ geminiBin } --policy ${ policyPath } --cwd ${ targetDir } -p "Address review comments and fix failing tests for PR ${ prNumber } . Repeat until CI is green." ` , dep : 'build' }
] ;
} else if ( action === 'ready' ) {
tasks = [
{ id : 'clean' , name : 'Clean Install' , cmd : ` npm run clean && npm ci ` } ,
{ id : 'preflight' , name : 'Full Preflight' , cmd : ` npm run preflight ` , dep : 'clean' } ,
{ id : 'conflicts' , name : 'Conflict Check' , cmd : ` git fetch origin main && git merge-base --is-ancestor origin/main HEAD || echo "CONFLICT" ` }
] ;
} else if ( action === 'open' ) {
console . log ( ` 🚀 Dropping into manual session for ${ branchName } ... ` ) ;
process . exit ( 0 ) ;
}
2026-03-13 17:40:39 -07:00
const state : Record < string , any > = { } ;
tasks . forEach ( t = > state [ t . id ] = { status : 'PENDING' } ) ;
2026-03-13 18:45:06 -07:00
return new Promise ( ( resolve ) = > {
function runTask ( task : any ) {
if ( task . dep && state [ task . dep ] . status !== 'SUCCESS' ) {
setTimeout ( ( ) = > runTask ( task ) , 1000 ) ;
return ;
}
state [ task . id ] . status = 'RUNNING' ;
const proc = spawn ( task . cmd , { shell : true , env : { . . . process . env , FORCE_COLOR : '1' } } ) ;
const logStream = fs . createWriteStream ( path . join ( logDir , ` ${ task . id } .log ` ) ) ;
proc . stdout . pipe ( logStream ) ;
proc . stderr . pipe ( logStream ) ;
proc . on ( 'close' , ( code ) = > {
const exitCode = code ? ? 0 ;
state [ task . id ] . status = exitCode === 0 ? 'SUCCESS' : 'FAILED' ;
fs . writeFileSync ( path . join ( logDir , ` ${ task . id } .exit ` ) , exitCode . toString ( ) ) ;
render ( ) ;
} ) ;
2026-03-13 17:40:39 -07:00
}
2026-03-13 18:45:06 -07:00
function render() {
console . clear ( ) ;
console . log ( ` ================================================== ` ) ;
2026-03-13 19:03:30 -07:00
console . log ( ` 🚀 Offload | ${ action . toUpperCase ( ) } | PR # ${ prNumber } ` ) ;
console . log ( ` 📂 Worktree: ${ targetDir } ` ) ;
2026-03-13 18:45:06 -07:00
console . log ( ` ================================================== \ n ` ) ;
tasks . forEach ( t = > {
const s = state [ t . id ] ;
const icon = s . status === 'SUCCESS' ? '✅' : s . status === 'FAILED' ? '❌' : s . status === 'RUNNING' ? '⏳' : '💤' ;
console . log ( ` ${ icon } ${ t . name . padEnd ( 20 ) } : ${ s . status } ` ) ;
} ) ;
2026-03-13 17:40:39 -07:00
2026-03-13 18:45:06 -07:00
const allDone = tasks . every ( t = > [ 'SUCCESS' , 'FAILED' ] . includes ( state [ t . id ] . status ) ) ;
if ( allDone ) {
2026-03-13 19:03:30 -07:00
console . log ( ` \ n✨ Playbook complete. Launching interactive session... ` ) ;
2026-03-13 18:45:06 -07:00
resolve ( 0 ) ;
}
2026-03-13 17:40:39 -07:00
}
2026-03-13 18:45:06 -07:00
tasks . filter ( t = > ! t . dep ) . forEach ( runTask ) ;
tasks . filter ( t = > t . dep ) . forEach ( runTask ) ;
const intervalId = setInterval ( render , 1500 ) ;
const checkAllDone = setInterval ( ( ) = > {
if ( tasks . every ( t = > [ 'SUCCESS' , 'FAILED' ] . includes ( state [ t . id ] . status ) ) ) {
clearInterval ( intervalId ) ;
clearInterval ( checkAllDone ) ;
}
} , 1000 ) ;
} ) ;
2026-03-13 17:40:39 -07:00
}
2026-03-13 18:45:06 -07:00
if ( import . meta . url === ` file:// ${ process . argv [ 1 ] } ` ) {
runWorker ( process . argv . slice ( 2 ) ) . catch ( console . error ) ;
}