feat(workspaces): implement resume logic and environment-based auth for faster setup

This commit is contained in:
mkorwel
2026-03-18 12:41:36 -07:00
parent 15db44f9ec
commit 911466bd03
+32 -20
View File
@@ -63,9 +63,33 @@ and full builds) to a dedicated, high-performance GCP worker.
console.log('📝 PHASE 1: CONFIGURATION'); console.log('📝 PHASE 1: CONFIGURATION');
console.log('--------------------------------------------------------------------------------'); console.log('--------------------------------------------------------------------------------');
const settingsPath = path.join(REPO_ROOT, '.gemini/workspaces/settings.json');
let settings: any = {};
let skipConfig = false;
if (fs.existsSync(settingsPath)) {
try {
settings = JSON.parse(fs.readFileSync(settingsPath, 'utf8'));
if (settings.workspace && !process.argv.includes('--reconfigure')) {
console.log(' ✅ Existing configuration found.');
const shouldSkip = await confirm(' ❓ Use existing configuration and skip to execution?');
if (shouldSkip) {
skipConfig = true;
}
}
} catch (e) {}
}
// 1. Project Identity // 1. Project Identity
const defaultProject = env.GOOGLE_CLOUD_PROJECT || env.WORKSPACE_PROJECT || ''; let projectId = settings.workspace?.projectId || '';
const projectId = await prompt('GCP Project ID', defaultProject, let zone = settings.workspace?.zone || 'us-west1-a';
let terminalTarget = settings.workspace?.terminalTarget || 'tab';
let upstreamRepo = settings.workspace?.upstreamRepo || 'google-gemini/gemini-cli';
let userFork = settings.workspace?.userFork || upstreamRepo;
if (!skipConfig) {
const defaultProject = env.GOOGLE_CLOUD_PROJECT || env.WORKSPACE_PROJECT || projectId || '';
projectId = await prompt('GCP Project ID', defaultProject,
'The GCP Project where your workspace worker will live. Your personal project is recommended.'); 'The GCP Project where your workspace worker will live. Your personal project is recommended.');
if (!projectId) { if (!projectId) {
@@ -73,18 +97,16 @@ and full builds) to a dedicated, high-performance GCP worker.
return 1; return 1;
} }
const zone = await prompt('Compute Zone', env.WORKSPACE_ZONE || 'us-west1-a', zone = await prompt('Compute Zone', env.WORKSPACE_ZONE || zone,
'The physical location of your worker. us-west1-a is the team default.'); 'The physical location of your worker. us-west1-a is the team default.');
const terminalTarget = await prompt('Terminal UI Target (foreground, background, tab, window)', env.WORKSPACE_TERM_TARGET || 'tab', terminalTarget = await prompt('Terminal UI Target (foreground, background, tab, window)', env.WORKSPACE_TERM_TARGET || terminalTarget,
'When you start a job in gemini-cli, should it run as a foreground shell, background shell (no attach), new iterm2 tab, or new iterm2 window?'); 'When you start a job in gemini-cli, should it run as a foreground shell, background shell (no attach), new iterm2 tab, or new iterm2 window?');
// 2. Repository Discovery (Dynamic) // 2. Repository Discovery (Dynamic)
console.log('\n🔍 Detecting repository origins...'); console.log('\n🔍 Detecting repository origins...');
const repoInfoRes = spawnSync('gh', ['repo', 'view', '--json', 'nameWithOwner,parent,isFork'], { stdio: 'pipe' }); const repoInfoRes = spawnSync('gh', ['repo', 'view', '--json', 'nameWithOwner,parent,isFork'], { stdio: 'pipe' });
let upstreamRepo = 'google-gemini/gemini-cli';
let userFork = '';
if (repoInfoRes.status === 0) { if (repoInfoRes.status === 0) {
try { try {
@@ -97,18 +119,7 @@ and full builds) to a dedicated, high-performance GCP worker.
const upstreamOwner = upstreamRepo.split('/')[0]; const upstreamOwner = upstreamRepo.split('/')[0];
const upstreamName = upstreamRepo.split('/')[1]; const upstreamName = upstreamRepo.split('/')[1];
// Use GraphQL to find your forks specifically. This is much faster than REST pagination. const gqlQuery = `query { viewer { repositories(first: 100, isFork: true, affiliations: OWNER) { nodes { nameWithOwner parent { nameWithOwner } } } } }`;
const gqlQuery = `query {
viewer {
repositories(first: 100, isFork: true, affiliations: OWNER) {
nodes {
nameWithOwner
parent { nameWithOwner }
}
}
}
}`;
const forksRes = spawnSync('gh', ['api', 'graphql', '-f', `query=${gqlQuery}`, '--jq', `.data.viewer.repositories.nodes[] | select(.parent.nameWithOwner == "${upstreamRepo}") | .nameWithOwner`], { stdio: 'pipe' }); const forksRes = spawnSync('gh', ['api', 'graphql', '-f', `query=${gqlQuery}`, '--jq', `.data.viewer.repositories.nodes[] | select(.parent.nameWithOwner == "${upstreamRepo}") | .nameWithOwner`], { stdio: 'pipe' });
const myForks = forksRes.stdout.toString().trim().split('\n').filter(Boolean); const myForks = forksRes.stdout.toString().trim().split('\n').filter(Boolean);
@@ -138,10 +149,11 @@ and full builds) to a dedicated, high-performance GCP worker.
console.log(` ✅ Upstream: ${upstreamRepo}`); console.log(` ✅ Upstream: ${upstreamRepo}`);
console.log(` ✅ Workspace: ${userFork}`); console.log(` ✅ Workspace: ${userFork}`);
}
// 3. Security & Auth // 3. Security & Auth (Always check for token if init is needed)
let githubToken = env.WORKSPACE_GH_TOKEN || ''; let githubToken = env.WORKSPACE_GH_TOKEN || '';
if (!githubToken) { if (!githubToken && !skipConfig) {
const hasToken = await confirm('\nDo you already have a GitHub Personal Access Token (PAT) with "Read/Write" access to contents & PRs?'); const hasToken = await confirm('\nDo you already have a GitHub Personal Access Token (PAT) with "Read/Write" access to contents & PRs?');
if (hasToken) { if (hasToken) {
githubToken = await prompt('Paste Scoped Token', ''); githubToken = await prompt('Paste Scoped Token', '');