feat: add --zone/--region and --size/--machine-type CLI flags (#2223)

Adds cross-cloud flags for specifying zone/region and instance size
directly from the command line instead of env vars:

  spawn claude gcp --zone us-east1-b --size e2-standard-4
  spawn claude digitalocean --region lon1 --size s-4vcpu-8gb
  spawn claude hetzner --zone ash --size cx32

Each flag maps to the appropriate cloud-specific env var:
  --zone/--region  → GCP_ZONE, DO_REGION, HETZNER_LOCATION, AWS_DEFAULT_REGION
  --size/--machine-type → GCP_MACHINE_TYPE, DO_DROPLET_SIZE, HETZNER_SERVER_TYPE, LIGHTSAIL_BUNDLE

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
L 2026-03-05 17:06:06 -05:00 committed by GitHub
parent ae584632f1
commit 9dff1296f0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 48 additions and 1 deletions

View file

@ -6,6 +6,8 @@ function getHelpUsageSection(): string {
spawn Interactive agent + cloud picker
spawn <agent> <cloud> Launch agent on cloud directly
spawn <agent> <cloud> --dry-run Preview what would be provisioned (or -n)
spawn <agent> <cloud> --zone <zone> Set zone/region (works for all clouds)
spawn <agent> <cloud> --size <type> Set instance size/type (works for all clouds)
spawn <agent> <cloud> --custom Show interactive size/region pickers
spawn <agent> <cloud> --headless Provision and exit (no interactive session)
spawn <agent> <cloud> --output json
@ -44,6 +46,9 @@ function getHelpExamplesSection(): string {
spawn codex sprite -p "Add tests" ${pc.dim("# Short form of --prompt")}
spawn openclaw aws -f instructions.txt
${pc.dim("# Read prompt from file (short for --prompt-file)")}
spawn claude gcp --zone us-east1-b ${pc.dim("# Use a specific GCP zone")}
spawn claude gcp --size e2-standard-4
${pc.dim("# Use a specific machine type")}
spawn opencode gcp --dry-run ${pc.dim("# Preview without provisioning")}
spawn claude hetzner --headless ${pc.dim("# Provision, print connection info, exit")}
spawn claude hetzner --output json ${pc.dim("# Structured JSON output on stdout")}

View file

@ -24,6 +24,10 @@ export const KNOWN_FLAGS = new Set([
"--clear",
"--custom",
"--reauth",
"--zone",
"--region",
"--machine-type",
"--size",
]);
/** Return the first unknown flag in args, or null if all are known/positional */

View file

@ -93,6 +93,8 @@ function checkUnknownFlags(args: string[]): void {
console.error(` ${pc.cyan("--headless")} Non-interactive mode (no prompts, no SSH session)`);
console.error(` ${pc.cyan("--output json")} Output structured JSON to stdout`);
console.error(` ${pc.cyan("--custom")} Show interactive size/region pickers`);
console.error(` ${pc.cyan("--zone, --region")} Set zone/region (e.g. us-east1-b, nyc3)`);
console.error(` ${pc.cyan("--size, --machine-type")} Set instance size (e.g. e2-standard-4, s-2vcpu-4gb)`);
console.error(` ${pc.cyan("--name")} Set the spawn/resource name`);
console.error(` ${pc.cyan("--reauth")} Force re-prompting for cloud credentials`);
console.error(` ${pc.cyan("--help, -h")} Show help information`);
@ -767,6 +769,42 @@ async function main(): Promise<void> {
process.env.SPAWN_NAME = nameFlag;
}
// Extract --zone / --region <value> flag (maps to cloud-specific env vars)
const [zoneFlag, zoneFilteredArgs] = extractFlagValue(
filteredArgs,
[
"--zone",
"--region",
],
"zone/region",
"spawn <agent> gcp --zone us-east1-b",
);
filteredArgs.splice(0, filteredArgs.length, ...zoneFilteredArgs);
if (zoneFlag) {
process.env.GCP_ZONE = zoneFlag;
process.env.DO_REGION = zoneFlag;
process.env.HETZNER_LOCATION = zoneFlag;
process.env.AWS_DEFAULT_REGION = zoneFlag;
}
// Extract --machine-type / --size <value> flag (maps to cloud-specific env vars)
const [sizeFlag, sizeFilteredArgs] = extractFlagValue(
filteredArgs,
[
"--machine-type",
"--size",
],
"machine type/size",
"spawn <agent> gcp --machine-type e2-standard-4",
);
filteredArgs.splice(0, filteredArgs.length, ...sizeFilteredArgs);
if (sizeFlag) {
process.env.GCP_MACHINE_TYPE = sizeFlag;
process.env.DO_DROPLET_SIZE = sizeFlag;
process.env.HETZNER_SERVER_TYPE = sizeFlag;
process.env.LIGHTSAIL_BUNDLE = sizeFlag;
}
// --output implies --headless
const effectiveHeadless = headless || !!outputFormat;