mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-03-30 16:00:41 -07:00
140 lines
4.0 KiB
TypeScript
140 lines
4.0 KiB
TypeScript
/**
|
|
* Offload Fleet Manager
|
|
*
|
|
* Manages dynamic GCP workers for offloading tasks.
|
|
*/
|
|
import { spawnSync } from 'child_process';
|
|
import path from 'path';
|
|
import fs from 'fs';
|
|
import { fileURLToPath } from 'url';
|
|
import { ProviderFactory } from './providers/ProviderFactory.ts';
|
|
|
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
const REPO_ROOT = path.resolve(__dirname, '../../../..');
|
|
|
|
const USER = process.env.USER || 'mattkorwel';
|
|
const INSTANCE_PREFIX = `gcli-offload-${USER}`;
|
|
const DEFAULT_ZONE = 'us-west1-a';
|
|
|
|
function getProjectId(): string {
|
|
const settingsPath = path.join(REPO_ROOT, '.gemini/offload/settings.json');
|
|
if (fs.existsSync(settingsPath)) {
|
|
try {
|
|
const settings = JSON.parse(fs.readFileSync(settingsPath, 'utf8'));
|
|
return settings.deepReview?.projectId;
|
|
} catch (e) {}
|
|
}
|
|
return process.env.GOOGLE_CLOUD_PROJECT || '';
|
|
}
|
|
|
|
async function listWorkers() {
|
|
const projectId = getProjectId();
|
|
if (!projectId) {
|
|
console.error('❌ Project ID not found. Run "npm run offload:setup" first.');
|
|
return;
|
|
}
|
|
|
|
console.log(`🔍 Listing Offload Workers for ${USER} in ${projectId}...`);
|
|
|
|
spawnSync('gcloud', [
|
|
'compute', 'instances', 'list',
|
|
'--project', projectId,
|
|
'--filter', `name~^${INSTANCE_PREFIX}`,
|
|
'--format', 'table(name,zone,status,networkInterfaces[0].networkIP:label=INTERNAL_IP,creationTimestamp)'
|
|
], { stdio: 'inherit' });
|
|
}
|
|
|
|
async function provisionWorker() {
|
|
const projectId = getProjectId();
|
|
if (!projectId) {
|
|
console.error('❌ Project ID not found. Run "npm run offload:setup" first.');
|
|
return;
|
|
}
|
|
|
|
const provider = ProviderFactory.getProvider({
|
|
projectId: projectId,
|
|
zone: DEFAULT_ZONE,
|
|
instanceName: INSTANCE_PREFIX
|
|
});
|
|
|
|
const status = await provider.getStatus();
|
|
if (status.status !== 'UNKNOWN' && status.status !== 'ERROR') {
|
|
console.log(`✅ Worker ${INSTANCE_PREFIX} already exists and is ${status.status}.`);
|
|
return;
|
|
}
|
|
|
|
await provider.provision();
|
|
}
|
|
|
|
async function stopWorker() {
|
|
const projectId = getProjectId();
|
|
const provider = ProviderFactory.getProvider({
|
|
projectId: projectId,
|
|
zone: DEFAULT_ZONE,
|
|
instanceName: INSTANCE_PREFIX
|
|
});
|
|
|
|
console.log(`🛑 Stopping offload worker: ${INSTANCE_PREFIX}...`);
|
|
await provider.stop();
|
|
}
|
|
|
|
async function remoteStatus() {
|
|
const settingsPath = path.join(REPO_ROOT, '.gemini/offload/settings.json');
|
|
if (!fs.existsSync(settingsPath)) {
|
|
console.error('❌ Settings not found. Run "npm run offload:setup" first.');
|
|
return;
|
|
}
|
|
const settings = JSON.parse(fs.readFileSync(settingsPath, 'utf8'));
|
|
const config = settings.deepReview;
|
|
|
|
const provider = ProviderFactory.getProvider({
|
|
projectId: config?.projectId || getProjectId(),
|
|
zone: config?.zone || DEFAULT_ZONE,
|
|
instanceName: INSTANCE_PREFIX
|
|
});
|
|
|
|
console.log(`📡 Fetching remote status from ${INSTANCE_PREFIX}...`);
|
|
await provider.exec('tsx .offload/scripts/status.ts');
|
|
}
|
|
|
|
async function rebuildWorker() {
|
|
const projectId = getProjectId();
|
|
console.log(`🔥 Rebuilding worker ${INSTANCE_PREFIX}...`);
|
|
|
|
const knownHostsPath = path.join(REPO_ROOT, '.gemini/offload_known_hosts');
|
|
if (fs.existsSync(knownHostsPath)) {
|
|
console.log(` - Clearing isolated known_hosts...`);
|
|
fs.unlinkSync(knownHostsPath);
|
|
}
|
|
|
|
spawnSync('gcloud', ['compute', 'instances', 'delete', INSTANCE_PREFIX, '--project', projectId, '--zone', DEFAULT_ZONE, '--quiet'], { stdio: 'inherit' });
|
|
await provisionWorker();
|
|
}
|
|
|
|
async function main() {
|
|
const action = process.argv[2] || 'list';
|
|
|
|
switch (action) {
|
|
case 'list':
|
|
await listWorkers();
|
|
break;
|
|
case 'provision':
|
|
await provisionWorker();
|
|
break;
|
|
case 'rebuild':
|
|
await rebuildWorker();
|
|
break;
|
|
case 'stop':
|
|
await stopWorker();
|
|
break;
|
|
case 'status':
|
|
await remoteStatus();
|
|
break;
|
|
default:
|
|
console.error(`❌ Unknown fleet action: ${action}`);
|
|
process.exit(1);
|
|
}
|
|
}
|
|
|
|
main().catch(console.error);
|