From 7ee56e7cfd36d079b87209764ce5486d27320ee1 Mon Sep 17 00:00:00 2001 From: mkorwel Date: Sat, 14 Mar 2026 09:23:40 -0700 Subject: [PATCH] feat(offload): finalize high-performance architecture with fast-path SSH and worktrees --- .gemini/settings.json | 10 +- .gemini/skills/offload/scripts/clean.ts | 33 ++--- .../skills/offload/scripts/orchestrator.ts | 95 ++++--------- .gemini/skills/offload/scripts/setup.ts | 132 ++++++++++++++---- .../offload/tests/orchestration.test.ts | 7 +- 5 files changed, 159 insertions(+), 118 deletions(-) diff --git a/.gemini/settings.json b/.gemini/settings.json index 12b475dc7c..1020c4a033 100644 --- a/.gemini/settings.json +++ b/.gemini/settings.json @@ -11,12 +11,10 @@ "deepReview": { "projectId": "gemini-cli-team-quota", "zone": "us-west1-a", - "machineType": "n2-standard-8", - "terminalType": "iterm2", - "syncAuth": true, - "setupType": "isolated", - "geminiSetup": "isolated", - "ghSetup": "isolated" + "remoteHost": "gcli-worker", + "remoteHome": "/home/mattkorwel_google_com", + "remoteWorkDir": "/home/mattkorwel_google_com/dev/main", + "terminalType": "iterm2" } } } \ No newline at end of file diff --git a/.gemini/skills/offload/scripts/clean.ts b/.gemini/skills/offload/scripts/clean.ts index bb0d0bddd0..451178119f 100644 --- a/.gemini/skills/offload/scripts/clean.ts +++ b/.gemini/skills/offload/scripts/clean.ts @@ -1,5 +1,7 @@ /** - * Universal Deep Review Cleanup (Local) + * Universal Offload Cleanup (Local) + * + * Cleans up tmux sessions and workspace on the GCE worker. */ import { spawnSync } from 'child_process'; import path from 'path'; @@ -23,7 +25,7 @@ async function confirm(question: string): Promise { export async function runCleanup() { const settingsPath = path.join(REPO_ROOT, '.gemini/settings.json'); if (!fs.existsSync(settingsPath)) { - console.error('โŒ Settings not found. Run "npm run review:setup" first.'); + console.error('โŒ Settings not found. Run "npm run offload:setup" first.'); return 1; } @@ -31,33 +33,32 @@ export async function runCleanup() { const config = settings.maintainer?.deepReview; if (!config) { - console.error('โŒ Deep Review configuration not found.'); + console.error('โŒ Offload configuration not found.'); return 1; } - const { remoteHost, remoteWorkDir } = config; + const { projectId, zone } = config; + const targetVM = `gcli-offload-${process.env.USER || 'mattkorwel'}`; - console.log(`๐Ÿงน Starting cleanup for ${remoteHost}:${remoteWorkDir}...`); + console.log(`๐Ÿงน Starting cleanup for ${targetVM}...`); // 1. Standard Cleanup console.log(' - Killing remote tmux sessions...'); - spawnSync('ssh', [remoteHost, 'tmux kill-server'], { shell: true }); + spawnSync(`ssh ${remoteHost} "tmux kill-server"`, { shell: true }); - console.log(' - Removing PR directories...'); - // Find all directories in the work dir that aren't .gemini and delete them - const dirCleanup = `find ${remoteWorkDir} -mindepth 1 -maxdepth 1 -type d ! -name ".gemini" -exec rm -rf {} +`; - spawnSync('ssh', [remoteHost, dirCleanup], { shell: true }); + console.log(' - Cleaning up Git Worktrees...'); + spawnSync(`ssh ${remoteHost} "cd ~/dev/main && git worktree prune"`, { shell: true }); + spawnSync(`ssh ${remoteHost} "rm -rf ~/dev/worktrees/*"`, { shell: true }); - console.log('โœ… Standard cleanup complete.'); + console.log('โœ… Remote environment cleared.'); // 2. Full Wipe Option - const shouldWipe = await confirm('\nWould you like to COMPLETELY remove the work directory from the remote machine?'); + const shouldWipe = await confirm('\nWould you like to COMPLETELY wipe the remote workspace directory?'); if (shouldWipe) { - console.log(`๐Ÿ”ฅ Wiping ${remoteWorkDir}...`); - const wipeCmd = `rm -rf ${remoteWorkDir}`; - spawnSync('ssh', [remoteHost, wipeCmd], { stdio: 'inherit', shell: true }); - console.log('โœ… Remote directory wiped.'); + console.log(`๐Ÿ”ฅ Wiping ~/.offload/workspace...`); + spawnSync(`gcloud compute ssh ${targetVM} --project ${projectId} --zone ${zone} --command "rm -rf ~/.offload/workspace && mkdir -p ~/.offload/workspace"`, { stdio: 'inherit', shell: true }); + console.log('โœ… Remote workspace wiped.'); } return 0; } diff --git a/.gemini/skills/offload/scripts/orchestrator.ts b/.gemini/skills/offload/scripts/orchestrator.ts index 4577a08351..7138abd0a8 100644 --- a/.gemini/skills/offload/scripts/orchestrator.ts +++ b/.gemini/skills/offload/scripts/orchestrator.ts @@ -1,7 +1,7 @@ /** * Universal Offload Orchestrator (Local) * - * Automatically detects and connects to your dynamic GCE fleet. + * Automatically connects to your dedicated worker and launches the task. */ import { spawnSync } from 'child_process'; import path from 'path'; @@ -22,93 +22,54 @@ export async function runOrchestrator(args: string[], env: NodeJS.ProcessEnv = p return 1; } - // 1. Load GCP Settings + // 1. Load Settings const settingsPath = path.join(REPO_ROOT, '.gemini/settings.json'); - if (!fs.existsSync(settingsPath)) { - console.error('โŒ Settings not found. Run "npm run offload:setup" first.'); - return 1; - } const settings = JSON.parse(fs.readFileSync(settingsPath, 'utf8')); const config = settings.maintainer?.deepReview; if (!config) { - console.error('โŒ Fleet settings not found. Run "npm run offload:setup" first.'); + console.error('โŒ Settings not found. Run "npm run offload:setup" first.'); return 1; } - const { projectId, zone, terminalType, syncAuth } = config; + const { projectId, zone, remoteHost, remoteHome, remoteWorkDir } = config; const targetVM = `gcli-offload-${env.USER || 'mattkorwel'}`; - console.log(`๐Ÿ” Connecting to offload worker: ${targetVM}...`); - - // 1. Get remote HOME and Status - const infoCheck = spawnSync(`gcloud compute ssh ${targetVM} --project ${projectId} --zone ${zone} --command "echo \$HOME && gcloud compute instances describe ${targetVM} --project ${projectId} --zone ${zone} --format='get(status)'"`, { shell: true }); - const infoOutput = infoCheck.stdout.toString().trim().split('\n'); - const remoteHome = infoOutput[0] || '/home/ubuntu'; - const status = infoOutput[infoOutput.length - 1] || 'RUNNING'; - - console.log(`DEBUG: Remote Home: ${remoteHome}, Status: ${status}`); + // 2. Wake Worker + const statusCheck = spawnSync(`gcloud compute instances describe ${targetVM} --project ${projectId} --zone ${zone} --format="get(status)"`, { shell: true }); + const status = statusCheck.stdout.toString().trim(); if (status !== 'RUNNING' && status !== 'PROVISIONING' && status !== 'STAGING') { - console.log(`โš ๏ธ Worker ${targetVM} is ${status}. Starting it now...`); + console.log(`โš ๏ธ Worker ${targetVM} is ${status}. Waking it up...`); spawnSync(`gcloud compute instances start ${targetVM} --project ${projectId} --zone ${zone}`, { shell: true, stdio: 'inherit' }); } - const remoteWorkDir = `${remoteHome}/.offload/workspace`; - const ISOLATED_GEMINI = `${remoteHome}/.offload/gemini-cli-config`; - const ISOLATED_GH = `${remoteHome}/.offload/gh-cli-config`; - const remotePolicyPath = `${ISOLATED_GEMINI}/policies/offload-policy.toml`; - + const remotePolicyPath = `${remoteHome}/.gemini/policies/offload-policy.toml`; + const persistentScripts = `${remoteHome}/.offload/scripts`; const sessionName = `offload-${prNumber}-${action}`; - // Fetch Metadata (local) - console.log(`๐Ÿ” Fetching metadata for ${action === 'implement' ? 'Issue' : 'PR'} #${prNumber}...`); - const ghCmd = action === 'implement' - ? `gh issue view ${prNumber} --json title -q .title` - : `gh pr view ${prNumber} --json headRefName -q .headRefName`; + // 3. Remote Context Setup (Parallel Worktree, NO symlinking) + console.log(`๐Ÿš€ Provisioning clean worktree for ${action} on PR #${prNumber}...`); + const remoteWorktreeDir = `${remoteHome}/dev/worktrees/offload-${prNumber}-${action}`; - const ghView = spawnSync(ghCmd, { shell: true }); - const metaName = ghView.stdout.toString().trim() || `task-${prNumber}`; - const branchName = action === 'implement' ? `impl-${prNumber}` : metaName; - console.log(`DEBUG: Branch name for session: ${branchName}`); + const setupCmd = ` + mkdir -p ${remoteHome}/dev/worktrees && \ + cd ${remoteWorkDir} && \ + git fetch origin pull/${prNumber}/head && \ + git worktree add -f ${remoteWorktreeDir} FETCH_HEAD + `; - console.log(`๐Ÿ“ฆ Synchronizing with ${targetVM}...`); - spawnSync(`gcloud compute ssh ${targetVM} --project ${projectId} --zone ${zone} --command "mkdir -p ${remoteWorkDir} ${ISOLATED_GEMINI}/policies/"`, { shell: true }); + spawnSync(`ssh ${remoteHost} ${q(setupCmd)}`, { shell: true, stdio: 'inherit' }); - // Sync manifests and scripts - const rsyncBase = `rsync -avz -e "gcloud compute ssh --project ${projectId} --zone ${zone}"`; - spawnSync(`${rsyncBase} package.json package-lock.json .gemini/skills/offload/policy.toml ${targetVM}:${remoteWorkDir}/`, { shell: true }); - spawnSync(`${rsyncBase} .gemini/skills/offload/policy.toml ${targetVM}:${remotePolicyPath}`, { shell: true }); - spawnSync(`${rsyncBase} --delete .gemini/skills/offload/scripts/ ${targetVM}:${remoteWorkDir}/.gemini/skills/offload/scripts/`, { shell: true }); - - if (syncAuth) { - const homeDir = env.HOME || ''; - const localGeminiDir = path.join(homeDir, '.gemini'); - const syncFiles = ['google_accounts.json', 'settings.json']; - for (const f of syncFiles) { - const lp = path.join(localGeminiDir, f); - if (fs.existsSync(lp)) { - spawnSync(`rsync -avz -e "gcloud compute ssh --project ${projectId} --zone ${zone}" ${lp} ${targetVM}:${ISOLATED_GEMINI}/${f}`, { shell: true }); - } - } - } - - // 4. Construct Command - const remoteWorker = `export GEMINI_CLI_HOME=${ISOLATED_GEMINI} && export GH_CONFIG_DIR=${ISOLATED_GH} && [ -d node_modules ] || npm install --no-audit --no-fund && node_modules/.bin/tsx .gemini/skills/offload/scripts/entrypoint.ts ${prNumber} ${branchName} ${remotePolicyPath} ${action}`; - const tmuxCmd = `cd ${remoteWorkDir} && ${remoteWorker}; exec $SHELL`; - - const gcloudPath = spawnSync('which', ['gcloud'], { stdio: 'pipe' }).stdout.toString().trim() || 'gcloud'; + // Use global tsx for the runner + const remoteWorker = `tsx ${persistentScripts}/entrypoint.ts ${prNumber} remote-branch ${remotePolicyPath} ${action}`; + const tmuxCmd = `cd ${remoteWorktreeDir} && ${remoteWorker}; exec $SHELL`; const sshInternal = `tmux attach-session -t ${sessionName} 2>/dev/null || tmux new-session -s ${sessionName} -n 'offload' ${q(tmuxCmd)}`; - const finalSSH = `${gcloudPath} compute ssh ${targetVM} --project ${projectId} --zone ${zone} -- -t ${q(sshInternal)}`; + const finalSSH = `ssh -t ${remoteHost} ${q(sshInternal)}`; - console.log(`DEBUG: Final SSH command: ${finalSSH}`); - - // 5. Terminal Automation + // 4. Open in iTerm2 const isWithinGemini = !!env.GEMINI_CLI || !!env.GEMINI_SESSION_ID || !!env.GCLI_SESSION_ID; - console.log(`DEBUG: isWithinGemini: ${isWithinGemini}`); - - if (isWithinGemini && terminalType === 'iterm2') { - // Write the command to a temp file to avoid AppleScript/Shell mangling + if (isWithinGemini) { const tempCmdPath = path.join(process.env.TMPDIR || '/tmp', `offload-ssh-${prNumber}.sh`); fs.writeFileSync(tempCmdPath, `#!/bin/bash\n${finalSSH}\nrm "$0"`, { mode: 0o755 }); @@ -124,12 +85,10 @@ export async function runOrchestrator(args: string[], env: NodeJS.ProcessEnv = p end run `; spawnSync('osascript', ['-', tempCmdPath], { input: appleScript }); - console.log(`โœ… iTerm2 window opened on ${targetVM}.`); + console.log(`โœ… iTerm2 window opened on ${remoteHost}.`); return 0; } - - console.log('๐Ÿš€ Launching interactive session...'); spawnSync(finalSSH, { stdio: 'inherit', shell: true }); return 0; } diff --git a/.gemini/skills/offload/scripts/setup.ts b/.gemini/skills/offload/scripts/setup.ts index 3494a00fbc..13448c639d 100644 --- a/.gemini/skills/offload/scripts/setup.ts +++ b/.gemini/skills/offload/scripts/setup.ts @@ -1,11 +1,12 @@ /** * Universal Offload Onboarding (Local) * - * Configures the GCP Project and Fleet defaults. + * Configures the GCP Project and performs one-time initialization of the worker. */ import { spawnSync } from 'child_process'; import path from 'path'; import fs from 'fs'; +import os from 'os'; import { fileURLToPath } from 'url'; import readline from 'readline'; @@ -33,32 +34,115 @@ async function confirm(question: string): Promise { } export async function runSetup(env: NodeJS.ProcessEnv = process.env) { - console.log('\n๐ŸŒŸ Initializing GCE Offload Fleet Settings...'); + console.log('\n๐ŸŒŸ Initializing Dedicated Offload Worker...'); const projectId = await prompt('GCP Project ID', 'gemini-cli-team-quota'); const zone = await prompt('Compute Zone', 'us-west1-a'); - const machineType = await prompt('Machine Type', 'n2-standard-8'); + const targetVM = `gcli-offload-${env.USER || 'mattkorwel'}`; - console.log(`๐Ÿ” Verifying project access for ${projectId}...`); - const projectCheck = spawnSync('gcloud', ['projects', 'describe', projectId], { stdio: 'pipe' }); - if (projectCheck.status !== 0) { - console.error(`โŒ Access denied to project: ${projectId}. Ensure you are logged in via gcloud.`); + console.log(`๐Ÿ” Verifying access and finding worker ${targetVM}...`); + const statusCheck = spawnSync(`gcloud compute instances describe ${targetVM} --project ${projectId} --zone ${zone} --format="json(status,networkInterfaces[0].accessConfigs[0].natIP)"`, { shell: true }); + + let instanceData: any; + try { + instanceData = JSON.parse(statusCheck.stdout.toString()); + } catch (e) { + console.error(`โŒ Worker ${targetVM} not found. Run "npm run offload:fleet provision" first.`); return 1; } - // Identity Synchronization Onboarding - console.log('\n๐Ÿ” Identity & Authentication:'); - const homeDir = env.HOME || ''; - const localAuth = path.join(homeDir, '.gemini/google_accounts.json'); - const hasAuth = fs.existsSync(localAuth); + const status = instanceData.status; + const publicIp = instanceData.networkInterfaces[0].accessConfigs[0].natIP; - let syncAuth = false; - if (hasAuth) { - console.log(` ๐Ÿ” Found local Gemini CLI credentials.`); - syncAuth = await confirm(' Would you like to automatically sync your local credentials to new fleet workers for seamless authentication?'); + if (status !== 'RUNNING') { + console.log(`โš ๏ธ Worker is ${status}. Starting it for initialization...`); + spawnSync(`gcloud compute instances start ${targetVM} --project ${projectId} --zone ${zone}`, { shell: true, stdio: 'inherit' }); } - const terminalType = await prompt('\nTerminal Automation (iterm2 / terminal / none)', 'iterm2'); + // 1. Configure Fast-Path SSH Alias + console.log(`\n๐Ÿš€ Configuring Fast-Path SSH Alias...`); + const sshAlias = 'gcli-worker'; + const sshConfigPath = path.join(os.homedir(), '.ssh/config'); + const sshEntry = ` +Host ${sshAlias} + HostName ${publicIp} + IdentityFile ~/.ssh/google_compute_engine + User ${env.USER || 'mattkorwel'}_google_com + CheckHostIP no + StrictHostKeyChecking no +`; + + let currentConfig = ''; + if (fs.existsSync(sshConfigPath)) currentConfig = fs.readFileSync(sshConfigPath, 'utf8'); + + if (!currentConfig.includes(`Host ${sshAlias}`)) { + fs.appendFileSync(sshConfigPath, sshEntry); + console.log(` โœ… Added '${sshAlias}' alias to ~/.ssh/config`); + } else { + console.log(` โ„น๏ธ '${sshAlias}' alias already exists in ~/.ssh/config`); + } + + // 1. Configure Fast-Path SSH Alias + // ... (unchanged) + + // Use the alias for remaining setup steps + const remoteHost = sshAlias; + const remoteHome = spawnSync(`ssh ${remoteHost} "pwd"`, { shell: true }).stdout.toString().trim(); + const remoteWorkDir = `${remoteHome}/dev/main`; + const persistentScripts = `${remoteHome}/.offload/scripts`; + + console.log(`\n๐Ÿ“ฆ Performing One-Time Synchronization...`); + spawnSync(`ssh ${remoteHost} "mkdir -p ${remoteWorkDir} ${remoteHome}/.gemini/policies ${persistentScripts}"`, { shell: true }); + + // Sync offload scripts to persistent location + console.log(' - Pushing offload logic to persistent worker directory...'); + spawnSync(`rsync -avz --delete .gemini/skills/offload/scripts/ ${remoteHost}:${persistentScripts}/`, { shell: true }); + spawnSync(`rsync -avz .gemini/skills/offload/policy.toml ${remoteHost}:${remoteHome}/.gemini/policies/offload-policy.toml`, { shell: true }); + + // 3. Sync Auth (Gemini) + if (await confirm('Sync Gemini accounts credentials?')) { + const homeDir = env.HOME || ''; + const lp = path.join(homeDir, '.gemini/google_accounts.json'); + if (fs.existsSync(lp)) { + console.log(` - Syncing .gemini/google_accounts.json...`); + spawnSync(`rsync -avz ${lp} ${remoteHost}:${remoteHome}/.gemini/google_accounts.json`, { shell: true }); + } + } + + // 4. Remote GitHub Login + if (await confirm('Authenticate GitHub CLI on the worker?')) { + console.log('\n๐Ÿ” Performing non-interactive GitHub CLI authentication on worker...'); + const localToken = spawnSync('gh', ['auth', 'token'], { stdio: 'pipe' }).stdout.toString().trim(); + if (!localToken) { + console.error('โŒ Could not find local GitHub token. Please log in locally first with "gh auth login".'); + return 1; + } + + // Pipe the local token to the remote worker's gh auth login + const loginCmd = `gh auth login --with-token --insecure-storage`; + const result = spawnSync(`echo ${localToken} | ssh ${remoteHost} ${JSON.stringify(loginCmd)}`, { shell: true, stdio: 'inherit' }); + + if (result.status === 0) { + console.log('โœ… GitHub CLI authenticated successfully on worker.'); + // Set git protocol to https by default for simplicity + spawnSync(`ssh ${remoteHost} "gh config set git_protocol https"`, { shell: true }); + } else { + console.error('โŒ GitHub CLI authentication failed on worker.'); + } + } + + // 5. Global Tooling & Clone + if (await confirm('Configure global tools (tsx, vitest) and clone repository?')) { + console.log('๐Ÿš€ Installing global developer tools...'); + spawnSync(`ssh ${remoteHost} "sudo npm install -g tsx vitest"`, { shell: true, stdio: 'inherit' }); + + console.log('๐Ÿš€ Cloning repository (blob-less) on worker...'); + const repoUrl = 'https://github.com/google-gemini/gemini-cli.git'; + const cloneCmd = `[ -d ${remoteWorkDir}/.git ] || git clone --filter=blob:none ${repoUrl} ${remoteWorkDir}`; + spawnSync(`ssh ${remoteHost} ${JSON.stringify(cloneCmd)}`, { shell: true, stdio: 'inherit' }); + + // We skip the full npm install here as requested; per-worktree builds will handle it if needed. + } // Save Settings const settingsPath = path.join(REPO_ROOT, '.gemini/settings.json'); @@ -70,18 +154,14 @@ export async function runSetup(env: NodeJS.ProcessEnv = process.env) { settings.maintainer.deepReview = { projectId, zone, - machineType, - terminalType, - syncAuth, - setupType: 'isolated', - geminiSetup: 'isolated', - ghSetup: 'isolated' + remoteHost, + remoteHome, + remoteWorkDir, + terminalType: 'iterm2' }; - fs.mkdirSync(path.dirname(settingsPath), { recursive: true }); fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2)); - console.log('\nโœ… GCE Fleet Onboarding complete! Settings saved to .gemini/settings.json'); - console.log(`๐Ÿ‘‰ Use 'npm run offload:fleet provision' to spin up your first worker.`); + console.log('\nโœ… Initialization complete! Your dedicated worker is ready via fast-path SSH.'); return 0; } diff --git a/.gemini/skills/offload/tests/orchestration.test.ts b/.gemini/skills/offload/tests/orchestration.test.ts index 5629cb0a41..618e8cfb14 100644 --- a/.gemini/skills/offload/tests/orchestration.test.ts +++ b/.gemini/skills/offload/tests/orchestration.test.ts @@ -38,8 +38,11 @@ describe('Offload Orchestration (GCE)', () => { // Default mock for gcloud instance info and describe vi.mocked(spawnSync).mockImplementation((cmd: any, args: any) => { const callInfo = JSON.stringify({ cmd, args }); - if (callInfo.includes('gcloud') && callInfo.includes('ssh') && callInfo.includes('echo $HOME')) { - return { status: 0, stdout: Buffer.from('/home/testuser\nRUNNING\n'), stderr: Buffer.from('') } as any; + if (callInfo.includes('compute') && callInfo.includes('describe')) { + return { status: 0, stdout: Buffer.from('RUNNING\n'), stderr: Buffer.from('') } as any; + } + if (callInfo.includes('gcloud') && callInfo.includes('ssh') && callInfo.includes('pwd')) { + return { status: 0, stdout: Buffer.from('/home/testuser\n'), stderr: Buffer.from('') } as any; } if (callInfo.includes('gh') && callInfo.includes('view')) { return { status: 0, stdout: Buffer.from('test-meta\n'), stderr: Buffer.from('') } as any;