mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-03-24 21:10:43 -07:00
feat(offload): address provisioning warnings and implement high-performance startup-script container
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* Universal Offload Cleanup (Local)
|
||||
*
|
||||
* Cleans up tmux sessions and workspace on the GCE worker.
|
||||
* Surgical or full cleanup of sessions and worktrees on the GCE worker.
|
||||
*/
|
||||
import { spawnSync } from 'child_process';
|
||||
import path from 'path';
|
||||
@@ -22,7 +22,10 @@ async function confirm(question: string): Promise<boolean> {
|
||||
});
|
||||
}
|
||||
|
||||
export async function runCleanup() {
|
||||
export async function runCleanup(args: string[]) {
|
||||
const prNumber = args[0];
|
||||
const action = args[1];
|
||||
|
||||
const settingsPath = path.join(REPO_ROOT, '.gemini/settings.json');
|
||||
if (!fs.existsSync(settingsPath)) {
|
||||
console.error('❌ Settings not found. Run "npm run offload:setup" first.');
|
||||
@@ -37,32 +40,49 @@ export async function runCleanup() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
const { projectId, zone } = config;
|
||||
const targetVM = `gcli-offload-${process.env.USER || 'mattkorwel'}`;
|
||||
const { remoteHost } = config;
|
||||
|
||||
console.log(`🧹 Starting cleanup for ${targetVM}...`);
|
||||
if (prNumber && action) {
|
||||
const sessionName = `offload-${prNumber}-${action}`;
|
||||
const worktreePath = `~/dev/worktrees/${sessionName}`;
|
||||
|
||||
console.log(`🧹 Surgically removing session and worktree for ${prNumber}-${action}...`);
|
||||
|
||||
// Kill specific tmux session
|
||||
spawnSync(`ssh ${remoteHost} "tmux kill-session -t ${sessionName} 2>/dev/null"`, { shell: true });
|
||||
|
||||
// Remove specific worktree
|
||||
spawnSync(`ssh ${remoteHost} "cd ~/dev/main && git worktree remove -f ${worktreePath} 2>/dev/null"`, { shell: true });
|
||||
spawnSync(`ssh ${remoteHost} "cd ~/dev/main && git worktree prune"`, { shell: true });
|
||||
|
||||
console.log(`✅ Cleaned up ${prNumber}-${action}.`);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// --- Bulk Cleanup (Old Behavior) ---
|
||||
console.log(`🧹 Starting BULK cleanup on ${remoteHost}...`);
|
||||
|
||||
// 1. Standard Cleanup
|
||||
console.log(' - Killing remote tmux sessions...');
|
||||
console.log(' - Killing ALL remote tmux sessions...');
|
||||
spawnSync(`ssh ${remoteHost} "tmux kill-server"`, { shell: true });
|
||||
|
||||
console.log(' - Cleaning up Git Worktrees...');
|
||||
console.log(' - Cleaning up ALL Git Worktrees...');
|
||||
spawnSync(`ssh ${remoteHost} "cd ~/dev/main && git worktree prune"`, { shell: true });
|
||||
spawnSync(`ssh ${remoteHost} "rm -rf ~/dev/worktrees/*"`, { shell: true });
|
||||
|
||||
console.log('✅ Remote environment cleared.');
|
||||
|
||||
// 2. Full Wipe Option
|
||||
const shouldWipe = await confirm('\nWould you like to COMPLETELY wipe the remote workspace directory?');
|
||||
const shouldWipe = await confirm('\nWould you like to COMPLETELY wipe the remote workspace (main clone)?');
|
||||
|
||||
if (shouldWipe) {
|
||||
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.');
|
||||
console.log(`🔥 Wiping ~/dev/main...`);
|
||||
spawnSync(`ssh ${remoteHost} "rm -rf ~/dev/main && mkdir -p ~/dev/main"`, { stdio: 'inherit', shell: true });
|
||||
console.log('✅ Remote hub wiped. You will need to run npm run offload:setup again.');
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (import.meta.url === `file://${process.argv[1]}`) {
|
||||
runCleanup().catch(console.error);
|
||||
runCleanup(process.argv.slice(2)).catch(console.error);
|
||||
}
|
||||
|
||||
@@ -41,29 +41,47 @@ async function provisionWorker() {
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(`🚀 Provisioning container-native offload worker: ${name}...`);
|
||||
console.log(`🚀 Provisioning high-performance container worker: ${name}...`);
|
||||
console.log(` - Image: ${imageUri}`);
|
||||
console.log(` - Disk: 200GB (High Performance)`);
|
||||
|
||||
// Use a startup script to run the container. This is the modern replacement
|
||||
// for the deprecated create-with-container agent.
|
||||
const startupScript = `#!/bin/bash
|
||||
# Install Docker
|
||||
apt-get update && apt-get install -y docker.io
|
||||
|
||||
# Authenticate to Artifact Registry
|
||||
# (The VM Service Account must have Artifact Registry Reader permissions)
|
||||
gcloud auth configure-docker us-docker.pkg.dev --quiet
|
||||
|
||||
# Pull and Run the maintainer container
|
||||
docker pull ${imageUri}
|
||||
docker run -d --name gemini-sandbox --restart always \\
|
||||
-v /home/$(whoami)/dev:/home/node/dev:rw \\
|
||||
-v /home/$(whoami)/.gemini:/home/node/.gemini:rw \\
|
||||
-v /home/$(whoami)/.offload:/home/node/.offload:rw \\
|
||||
${imageUri} /bin/bash -c "while true; do sleep 1000; done"
|
||||
`;
|
||||
|
||||
const result = spawnSync('gcloud', [
|
||||
'compute', 'instances', 'create-with-container', name,
|
||||
'compute', 'instances', 'create', name,
|
||||
'--project', PROJECT_ID,
|
||||
'--zone', zone,
|
||||
'--machine-type', 'n2-standard-8',
|
||||
'--container-image', imageUri,
|
||||
'--container-name', 'gemini-sandbox',
|
||||
'--container-restart-policy', 'always',
|
||||
'--container-mount-host-path', 'host-path=/home/$(whoami)/dev,mount-path=/home/node/dev,mode=rw',
|
||||
'--container-mount-host-path', 'host-path=/home/$(whoami)/.gemini,mount-path=/home/node/.gemini,mode=rw',
|
||||
'--container-mount-host-path', 'host-path=/home/$(whoami)/.offload,mount-path=/home/node/.offload,mode=rw',
|
||||
'--boot-disk-size', '50GB',
|
||||
'--image-family', 'ubuntu-2204-lts',
|
||||
'--image-project', 'ubuntu-os-cloud',
|
||||
'--boot-disk-size', '200GB',
|
||||
'--boot-disk-type', 'pd-balanced',
|
||||
'--metadata', `startup-script=${startupScript}`,
|
||||
'--labels', `owner=${USER.replace(/[^a-z0-9_-]/g, '_')},type=offload-worker`,
|
||||
'--tags', `gcli-offload-${USER}`,
|
||||
'--scopes', 'https://www.googleapis.com/auth/cloud-platform'
|
||||
], { stdio: 'inherit', shell: true });
|
||||
|
||||
if (result.status === 0) {
|
||||
console.log(`\n✅ Container worker ${name} is being provisioned.`);
|
||||
console.log(`👉 Access is managed via 'gcloud compute ssh --container'.`);
|
||||
console.log(`\n✅ Worker ${name} is being provisioned.`);
|
||||
console.log(`👉 Container 'gemini-sandbox' will start automatically once booted.`);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -55,9 +55,10 @@ function getStatus() {
|
||||
|
||||
console.log(`${pr.padEnd(10)} | ${action.padEnd(10)} | ${state.padEnd(12)} | ${id.padEnd(25)}`);
|
||||
if (state === '🏃 RUNNING') {
|
||||
console.log(` └─ Attach: npm run offload:attach ${pr} ${action} [--local]`);
|
||||
console.log(` └─ Logs: npm run offload:logs ${pr} ${action}`);
|
||||
console.log(` ├─ Attach: npm run offload:attach ${pr} ${action} [--local]`);
|
||||
console.log(` ├─ Logs: npm run offload:logs ${pr} ${action}`);
|
||||
}
|
||||
console.log(` └─ Remove: npm run offload:remove ${pr} ${action}`);
|
||||
});
|
||||
console.log(''.padEnd(100, '-'));
|
||||
}
|
||||
|
||||
@@ -71,6 +71,7 @@
|
||||
"offload:status": "npm run offload:fleet status",
|
||||
"offload:attach": "tsx .gemini/skills/offload/scripts/attach.ts",
|
||||
"offload:logs": "tsx .gemini/skills/offload/scripts/logs.ts",
|
||||
"offload:remove": "tsx .gemini/skills/offload/scripts/clean.ts",
|
||||
"pre-commit": "node scripts/pre-commit.js"
|
||||
},
|
||||
"overrides": {
|
||||
|
||||
Reference in New Issue
Block a user