From 7d11fdeb8c965af48bf6613c992dc327c35b6d95 Mon Sep 17 00:00:00 2001 From: mkorwel Date: Thu, 19 Mar 2026 00:21:41 -0700 Subject: [PATCH] feat(workspaces): implement unified scripts/workspaces.ts entry point and simplify commands --- MAINTAINER_ONBOARDING.md | 66 ++++++++++++++++++++++----------- package.json | 20 +++++----- scripts/workspaces.ts | 79 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 134 insertions(+), 31 deletions(-) create mode 100755 scripts/workspaces.ts diff --git a/MAINTAINER_ONBOARDING.md b/MAINTAINER_ONBOARDING.md index 58ff33761d..e78f111c91 100644 --- a/MAINTAINER_ONBOARDING.md +++ b/MAINTAINER_ONBOARDING.md @@ -1,51 +1,75 @@ # Gemini Workspaces: Maintainer Onboarding -Gemini Workspaces allow you to offload heavy tasks (PR reviews, agentic fixes, full builds) to a high-performance GCP worker. It uses a **Unified Data Disk** architecture to ensure your work persists even if the VM is deleted or recreated. +Gemini Workspaces allow you to offload heavy tasks (PR reviews, agentic fixes, +full builds) to a high-performance GCP worker. It uses a **Unified Data Disk** +architecture to ensure your work persists even if the VM is deleted or +recreated. ## 1. Local Prerequisites + Before starting, ensure you have: -* **GCloud CLI**: Authenticated (`gcloud auth login`). -* **GitHub CLI**: Authenticated (`gh auth login`). -* **Project Access**: A GCP Project ID where you have `Editor` or `Compute Admin` roles. + +- **GCloud CLI**: Authenticated (`gcloud auth login`). +- **GitHub CLI**: Authenticated (`gh auth login`). +- **Project Access**: A GCP Project ID where you have `Editor` or + `Compute Admin` roles. ## 2. Initialization -Run the setup script using `npx tsx` to ensure all dependencies are available: + +Run the setup script using the unified workspaces entry point: ```bash -npx tsx .gemini/skills/workspaces/scripts/setup.ts +npx tsx scripts/workspaces.ts setup ``` **What happens during setup:** -1. **Auth Discovery**: It will detect your `GEMINI_API_KEY` (from `~/.env`) and `GH_TOKEN`. + +1. **Auth Discovery**: It will detect your `GEMINI_API_KEY` (from `~/.env`) and + `GH_TOKEN`. 2. **Project Choice**: You will be prompted for your GCP Project and Zone. -3. **Infrastructure Check**: It verifies if your worker (`gcli-workspace-`) exists. -4. **SSH Magic**: It generates a local `.gemini/workspaces/ssh_config` for seamless access. +3. **Infrastructure Check**: It verifies if your worker + (`gcli-workspace-`) exists. +4. **SSH Magic**: It generates a local `.gemini/workspaces/ssh_config` for + seamless access. ## 3. Provisioning + If the setup informs you that the worker was not found, provision it: ```bash -npx tsx .gemini/skills/workspaces/scripts/fleet.ts provision +npx tsx scripts/workspaces.ts fleet provision ``` -*This creates a VM with a 10GB Boot Disk and a 200GB Data Disk. Initialization takes ~1 minute.* + +_This creates a VM with a 10GB Boot Disk and a 200GB Data Disk. Initialization +takes ~1 minute._ ## 4. Finalizing Remote Setup + Run the setup script one last time to clone the repo and sync credentials: ```bash -npx tsx .gemini/skills/workspaces/scripts/setup.ts +npx tsx scripts/workspaces.ts setup ``` -*When you see "ALL SYSTEMS GO!", your workspace is ready.* + +_When you see "ALL SYSTEMS GO!", your workspace is ready._ ## 5. Daily Usage -Once initialized, you can launch tasks directly through `npm`: -* **Review a PR**: `npm run workspace review` -* **Fix a PR**: `npm run workspace fix` -* **Check Status**: `npx tsx .gemini/skills/workspaces/scripts/status.ts` -* **Stop Worker**: `npx tsx .gemini/skills/workspaces/scripts/fleet.ts stop` (Recommended when finished to save cost). +Once initialized, you can launch tasks directly through `npm` or the entry +point: + +- **Review a PR**: `npm run workspace review` +- **Launch a Shell**: `npm run workspace:shell ` +- **Check Status**: `npm run workspace:status` +- **Cleanup All**: `npm run workspace:clean-all` +- **Kill Task**: `npm run workspace:kill ` +- **Stop Worker**: `npx tsx scripts/workspaces.ts fleet stop` (Recommended when + finished to save cost). ## Troubleshooting -* **Permission Denied (Docker)**: The orchestrator handles this by using `sudo docker` internally. -* **Dubious Ownership**: The system automatically adds `/mnt/disks/data/main` to Git's safe directory list. -* **Missing tsx**: Always prefer `npx tsx` when running scripts manually. + +- **Permission Denied (Docker)**: The orchestrator handles this by using + `sudo docker` internally. +- **Dubious Ownership**: The system automatically adds `/mnt/disks/data/main` to + Git's safe directory list. +- **Missing tsx**: Always prefer `npx tsx` when running scripts manually. diff --git a/package.json b/package.json index 8d842b8e8f..68f855a0bf 100644 --- a/package.json +++ b/package.json @@ -64,16 +64,16 @@ "telemetry": "node scripts/telemetry.js", "check:lockfile": "node scripts/check-lockfile.js", "clean": "node scripts/clean.js", - "workspace": "tsx .gemini/skills/workspaces/scripts/orchestrator.ts", - "workspace:setup": "tsx .gemini/skills/workspaces/scripts/setup.ts", - "workspace:shell": "tsx .gemini/skills/workspaces/scripts/orchestrator.ts shell", - "workspace:check": "tsx .gemini/skills/workspaces/scripts/check.ts", - "workspace:clean-all": "tsx .gemini/skills/workspaces/scripts/clean.ts", - "workspace:kill": "tsx .gemini/skills/workspaces/scripts/clean.ts", - "workspace:fleet": "tsx .gemini/skills/workspaces/scripts/fleet.ts", - "workspace:status": "tsx .gemini/skills/workspaces/scripts/status.ts", - "workspace:attach": "tsx .gemini/skills/workspaces/scripts/attach.ts", - "workspace:logs": "tsx .gemini/skills/workspaces/scripts/logs.ts", + "workspace": "tsx ./scripts/workspaces.ts", + "workspace:setup": "tsx ./scripts/workspaces.ts setup", + "workspace:shell": "tsx ./scripts/workspaces.ts shell", + "workspace:check": "tsx ./scripts/workspaces.ts check", + "workspace:clean-all": "tsx ./scripts/workspaces.ts clean-all", + "workspace:kill": "tsx ./scripts/workspaces.ts kill", + "workspace:fleet": "tsx ./scripts/workspaces.ts fleet", + "workspace:status": "tsx ./scripts/workspaces.ts status", + "workspace:attach": "tsx ./scripts/workspaces.ts attach", + "workspace:logs": "tsx ./scripts/workspaces.ts logs", "pre-commit": "node scripts/pre-commit.js" }, "overrides": { diff --git a/scripts/workspaces.ts b/scripts/workspaces.ts new file mode 100755 index 0000000000..d10326ed1a --- /dev/null +++ b/scripts/workspaces.ts @@ -0,0 +1,79 @@ +#!/usr/bin/env npx tsx +/** + * @license + * Copyright 2026 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ +import { spawnSync } from 'node:child_process'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); +const REPO_ROOT = path.resolve(__dirname, '..'); + +const commands: Record = { + setup: '.gemini/skills/workspaces/scripts/setup.ts', + shell: '.gemini/skills/workspaces/scripts/orchestrator.ts shell', + check: '.gemini/skills/workspaces/scripts/check.ts', + 'clean-all': '.gemini/skills/workspaces/scripts/clean.ts', + kill: '.gemini/skills/workspaces/scripts/clean.ts', + fleet: '.gemini/skills/workspaces/scripts/fleet.ts', + status: '.gemini/skills/workspaces/scripts/status.ts', + attach: '.gemini/skills/workspaces/scripts/attach.ts', + logs: '.gemini/skills/workspaces/scripts/logs.ts', +}; + +function printUsage() { + console.log('Gemini Workspaces Management CLI'); + console.log( + '\nUsage: scripts/workspaces.ts [args] [--open foreground|tab|window]', + ); + console.log('\nCommands:'); + console.log( + ' setup Initialize or reconfigure your remote worker', + ); + console.log(' [action] Launch a PR task (review, fix, ready)'); + console.log(' shell [id] Open an ad-hoc interactive session'); + console.log(' status See worker and session overview'); + console.log(' check Deep-dive into PR logs'); + console.log(' kill Surgical removal of a task'); + console.log(' clean-all Full remote cleanup'); + console.log(' fleet Manage VM life cycle (stop, provision)'); + process.exit(1); +} + +async function main() { + const args = process.argv.slice(2); + const cmd = args[0]; + + if (!cmd || cmd === '--help' || cmd === '-h') { + printUsage(); + } + + let scriptPath = commands[cmd]; + let finalArgs = args.slice(1); + + // Default: If it's a number, it's a PR orchestrator task + if (!scriptPath && /^\d+$/.test(cmd)) { + scriptPath = '.gemini/skills/workspaces/scripts/orchestrator.ts'; + finalArgs = args; // Pass the PR number as the first arg + } + + if (!scriptPath) { + console.error(`❌ Unknown command: ${cmd}`); + printUsage(); + } + + const [realScript, ...internalArgs] = scriptPath.split(' '); + const fullScriptPath = path.join(REPO_ROOT, realScript); + + const result = spawnSync( + 'npx', + ['tsx', fullScriptPath, ...internalArgs, ...finalArgs], + { stdio: 'inherit' }, + ); + + process.exit(result.status ?? 0); +} + +main().catch(console.error);