feat: SPAWN_CLI_DIR env var to force local source in e2e (#2015)

* feat: SPAWN_CLI_DIR env var to force local source in e2e and shell scripts

When SPAWN_CLI_DIR is set, the entire toolchain uses local TypeScript
source instead of downloading pre-bundled scripts from GitHub releases:

- e2e.sh: auto-sets SPAWN_CLI_DIR to repo root when running locally
- provision.sh: exports SPAWN_CLI_DIR into the headless subshell
- commands.ts: reads local shell scripts instead of fetching from CDN
- All 36 cloud/agent shell scripts: exec local main.ts when set

This enables e2e tests to validate local changes before they're released.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(security): add path traversal defense to SPAWN_CLI_DIR script loading

Canonicalize the path via realpathSync and verify it stays inside the
resolved CLI directory before reading. Prevents SPAWN_CLI_DIR from
being used to read arbitrary files via ../ traversal.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(security): harden SPAWN_CLI_DIR path traversal defense

- Validate cloud/agent names don't contain '..', '/' or '\' before
  constructing file paths
- Fix root-directory edge case in prefix check by handling trailing
  separator correctly

Agent: pr-maintainer
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: B <6723574+louisgv@users.noreply.github.com>
This commit is contained in:
Ahmed Abushagur 2026-02-28 01:14:36 -08:00 committed by GitHub
parent ee83e46d9b
commit d5461adc16
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
39 changed files with 276 additions and 33 deletions

View file

@ -1199,42 +1199,74 @@ export async function cmdRunHeadless(agent: string, cloud: string, opts: Headles
}
}
// Phase 2: Download script (exit code 2)
const url = `https://openrouter.ai/labs/spawn/${resolvedCloud}/${resolvedAgent}.sh`;
const ghUrl = `${RAW_BASE}/sh/${resolvedCloud}/${resolvedAgent}.sh`;
// Phase 2: Load script — prefer local source when SPAWN_CLI_DIR is set (exit code 2)
let scriptContent: string;
try {
const res = await fetch(url, {
signal: AbortSignal.timeout(FETCH_TIMEOUT),
});
if (res.ok) {
scriptContent = await res.text();
} else {
const ghRes = await fetch(ghUrl, {
const cliDir = process.env.SPAWN_CLI_DIR;
let localScriptResolved = "";
if (cliDir) {
// Reject cloud/agent names containing path traversal characters
const hasBadChars = (s: string) => s.includes("..") || s.includes("/") || s.includes("\\");
const safeCloud = !hasBadChars(resolvedCloud);
const safeAgent = !hasBadChars(resolvedAgent);
if (safeCloud && safeAgent) {
const resolvedCliDir = path.resolve(cliDir);
const candidatePath = path.join(resolvedCliDir, "sh", resolvedCloud, `${resolvedAgent}.sh`);
try {
const canonicalPath = fs.realpathSync(candidatePath);
// Ensure the resolved path stays inside the CLI dir (no path traversal)
const prefix = resolvedCliDir.endsWith(path.sep) ? resolvedCliDir : resolvedCliDir + path.sep;
if (canonicalPath.startsWith(prefix)) {
localScriptResolved = canonicalPath;
}
} catch {
// File doesn't exist — fall through to remote fetch
}
}
}
if (localScriptResolved) {
scriptContent = fs.readFileSync(localScriptResolved, "utf-8");
if (debug) {
console.error(`[headless] Using local script: ${localScriptResolved}`);
}
} else {
const url = `https://openrouter.ai/labs/spawn/${resolvedCloud}/${resolvedAgent}.sh`;
const ghUrl = `${RAW_BASE}/sh/${resolvedCloud}/${resolvedAgent}.sh`;
try {
const res = await fetch(url, {
signal: AbortSignal.timeout(FETCH_TIMEOUT),
});
if (!ghRes.ok) {
headlessError(
resolvedAgent,
resolvedCloud,
"DOWNLOAD_ERROR",
`Script not found (HTTP ${res.status} primary, ${ghRes.status} fallback)`,
outputFormat,
2,
);
if (res.ok) {
scriptContent = await res.text();
} else {
const ghRes = await fetch(ghUrl, {
signal: AbortSignal.timeout(FETCH_TIMEOUT),
});
if (!ghRes.ok) {
headlessError(
resolvedAgent,
resolvedCloud,
"DOWNLOAD_ERROR",
`Script not found (HTTP ${res.status} primary, ${ghRes.status} fallback)`,
outputFormat,
2,
);
}
scriptContent = await ghRes.text();
}
scriptContent = await ghRes.text();
} catch (err) {
headlessError(
resolvedAgent,
resolvedCloud,
"DOWNLOAD_ERROR",
`Failed to download script: ${getErrorMessage(err)}`,
outputFormat,
2,
);
}
} catch (err) {
headlessError(
resolvedAgent,
resolvedCloud,
"DOWNLOAD_ERROR",
`Failed to download script: ${getErrorMessage(err)}`,
outputFormat,
2,
);
}
// Phase 3: Execute script (exit code 1)

View file

@ -15,6 +15,11 @@ _ensure_bun
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)"
# SPAWN_CLI_DIR override — force local source (used by e2e tests)
if [[ -n "${SPAWN_CLI_DIR:-}" && -f "$SPAWN_CLI_DIR/packages/cli/src/aws/main.ts" ]]; then
exec bun run "$SPAWN_CLI_DIR/packages/cli/src/aws/main.ts" claude "$@"
fi
# Local checkout — run from source
if [[ -n "$SCRIPT_DIR" && -f "$SCRIPT_DIR/../../packages/cli/src/aws/main.ts" ]]; then
exec bun run "$SCRIPT_DIR/../../packages/cli/src/aws/main.ts" claude "$@"

View file

@ -15,6 +15,11 @@ _ensure_bun
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)"
# SPAWN_CLI_DIR override — force local source (used by e2e tests)
if [[ -n "${SPAWN_CLI_DIR:-}" && -f "$SPAWN_CLI_DIR/packages/cli/src/aws/main.ts" ]]; then
exec bun run "$SPAWN_CLI_DIR/packages/cli/src/aws/main.ts" codex "$@"
fi
# Local checkout — run from source
if [[ -n "$SCRIPT_DIR" && -f "$SCRIPT_DIR/../../packages/cli/src/aws/main.ts" ]]; then
exec bun run "$SCRIPT_DIR/../../packages/cli/src/aws/main.ts" codex "$@"

View file

@ -16,6 +16,11 @@ _ensure_bun
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)"
# SPAWN_CLI_DIR override — force local source (used by e2e tests)
if [[ -n "${SPAWN_CLI_DIR:-}" && -f "$SPAWN_CLI_DIR/packages/cli/src/aws/main.ts" ]]; then
exec bun run "$SPAWN_CLI_DIR/packages/cli/src/aws/main.ts" kilocode "$@"
fi
# Local checkout — run from source
if [[ -n "$SCRIPT_DIR" && -f "$SCRIPT_DIR/../../packages/cli/src/aws/main.ts" ]]; then
exec bun run "$SCRIPT_DIR/../../packages/cli/src/aws/main.ts" kilocode "$@"

View file

@ -15,6 +15,11 @@ _ensure_bun
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)"
# SPAWN_CLI_DIR override — force local source (used by e2e tests)
if [[ -n "${SPAWN_CLI_DIR:-}" && -f "$SPAWN_CLI_DIR/packages/cli/src/aws/main.ts" ]]; then
exec bun run "$SPAWN_CLI_DIR/packages/cli/src/aws/main.ts" openclaw "$@"
fi
# Local checkout — run from source
if [[ -n "$SCRIPT_DIR" && -f "$SCRIPT_DIR/../../packages/cli/src/aws/main.ts" ]]; then
exec bun run "$SCRIPT_DIR/../../packages/cli/src/aws/main.ts" openclaw "$@"

View file

@ -15,6 +15,11 @@ _ensure_bun
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)"
# SPAWN_CLI_DIR override — force local source (used by e2e tests)
if [[ -n "${SPAWN_CLI_DIR:-}" && -f "$SPAWN_CLI_DIR/packages/cli/src/aws/main.ts" ]]; then
exec bun run "$SPAWN_CLI_DIR/packages/cli/src/aws/main.ts" opencode "$@"
fi
# Local checkout — run from source
if [[ -n "$SCRIPT_DIR" && -f "$SCRIPT_DIR/../../packages/cli/src/aws/main.ts" ]]; then
exec bun run "$SCRIPT_DIR/../../packages/cli/src/aws/main.ts" opencode "$@"

View file

@ -15,6 +15,11 @@ _ensure_bun
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)"
# SPAWN_CLI_DIR override — force local source (used by e2e tests)
if [[ -n "${SPAWN_CLI_DIR:-}" && -f "$SPAWN_CLI_DIR/packages/cli/src/aws/main.ts" ]]; then
exec bun run "$SPAWN_CLI_DIR/packages/cli/src/aws/main.ts" zeroclaw "$@"
fi
# Local checkout — run from source
if [[ -n "$SCRIPT_DIR" && -f "$SCRIPT_DIR/../../packages/cli/src/aws/main.ts" ]]; then
exec bun run "$SCRIPT_DIR/../../packages/cli/src/aws/main.ts" zeroclaw "$@"

View file

@ -15,6 +15,11 @@ _ensure_bun
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)"
# SPAWN_CLI_DIR override — force local source (used by e2e tests)
if [[ -n "${SPAWN_CLI_DIR:-}" && -f "$SPAWN_CLI_DIR/packages/cli/src/daytona/main.ts" ]]; then
exec bun run "$SPAWN_CLI_DIR/packages/cli/src/daytona/main.ts" claude "$@"
fi
# Local checkout — run from source
if [[ -n "$SCRIPT_DIR" && -f "$SCRIPT_DIR/../../packages/cli/src/daytona/main.ts" ]]; then
exec bun run "$SCRIPT_DIR/../../packages/cli/src/daytona/main.ts" claude "$@"

View file

@ -15,6 +15,11 @@ _ensure_bun
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)"
# SPAWN_CLI_DIR override — force local source (used by e2e tests)
if [[ -n "${SPAWN_CLI_DIR:-}" && -f "$SPAWN_CLI_DIR/packages/cli/src/daytona/main.ts" ]]; then
exec bun run "$SPAWN_CLI_DIR/packages/cli/src/daytona/main.ts" codex "$@"
fi
# Local checkout — run from source
if [[ -n "$SCRIPT_DIR" && -f "$SCRIPT_DIR/../../packages/cli/src/daytona/main.ts" ]]; then
exec bun run "$SCRIPT_DIR/../../packages/cli/src/daytona/main.ts" codex "$@"

View file

@ -15,6 +15,11 @@ _ensure_bun
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)"
# SPAWN_CLI_DIR override — force local source (used by e2e tests)
if [[ -n "${SPAWN_CLI_DIR:-}" && -f "$SPAWN_CLI_DIR/packages/cli/src/daytona/main.ts" ]]; then
exec bun run "$SPAWN_CLI_DIR/packages/cli/src/daytona/main.ts" kilocode "$@"
fi
# Local checkout — run from source
if [[ -n "$SCRIPT_DIR" && -f "$SCRIPT_DIR/../../packages/cli/src/daytona/main.ts" ]]; then
exec bun run "$SCRIPT_DIR/../../packages/cli/src/daytona/main.ts" kilocode "$@"

View file

@ -15,6 +15,11 @@ _ensure_bun
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)"
# SPAWN_CLI_DIR override — force local source (used by e2e tests)
if [[ -n "${SPAWN_CLI_DIR:-}" && -f "$SPAWN_CLI_DIR/packages/cli/src/daytona/main.ts" ]]; then
exec bun run "$SPAWN_CLI_DIR/packages/cli/src/daytona/main.ts" openclaw "$@"
fi
# Local checkout — run from source
if [[ -n "$SCRIPT_DIR" && -f "$SCRIPT_DIR/../../packages/cli/src/daytona/main.ts" ]]; then
exec bun run "$SCRIPT_DIR/../../packages/cli/src/daytona/main.ts" openclaw "$@"

View file

@ -15,6 +15,11 @@ _ensure_bun
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)"
# SPAWN_CLI_DIR override — force local source (used by e2e tests)
if [[ -n "${SPAWN_CLI_DIR:-}" && -f "$SPAWN_CLI_DIR/packages/cli/src/daytona/main.ts" ]]; then
exec bun run "$SPAWN_CLI_DIR/packages/cli/src/daytona/main.ts" opencode "$@"
fi
# Local checkout — run from source
if [[ -n "$SCRIPT_DIR" && -f "$SCRIPT_DIR/../../packages/cli/src/daytona/main.ts" ]]; then
exec bun run "$SCRIPT_DIR/../../packages/cli/src/daytona/main.ts" opencode "$@"

View file

@ -15,6 +15,11 @@ _ensure_bun
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)"
# SPAWN_CLI_DIR override — force local source (used by e2e tests)
if [[ -n "${SPAWN_CLI_DIR:-}" && -f "$SPAWN_CLI_DIR/packages/cli/src/daytona/main.ts" ]]; then
exec bun run "$SPAWN_CLI_DIR/packages/cli/src/daytona/main.ts" zeroclaw "$@"
fi
# Local checkout — run from source
if [[ -n "$SCRIPT_DIR" && -f "$SCRIPT_DIR/../../packages/cli/src/daytona/main.ts" ]]; then
exec bun run "$SCRIPT_DIR/../../packages/cli/src/daytona/main.ts" zeroclaw "$@"

View file

@ -62,6 +62,12 @@ _ensure_bun
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)"
# SPAWN_CLI_DIR override — force local source (used by e2e tests)
if [[ -n "${SPAWN_CLI_DIR:-}" && -f "$SPAWN_CLI_DIR/packages/cli/src/digitalocean/main.ts" ]]; then
_run_with_restart bun run "$SPAWN_CLI_DIR/packages/cli/src/digitalocean/main.ts" "$_AGENT_NAME" "$@"
exit $?
fi
# Local checkout — run from source
if [[ -n "$SCRIPT_DIR" && -f "$SCRIPT_DIR/../../packages/cli/src/digitalocean/main.ts" ]]; then
_run_with_restart bun run "$SCRIPT_DIR/../../packages/cli/src/digitalocean/main.ts" "$_AGENT_NAME" "$@"

View file

@ -62,6 +62,12 @@ _ensure_bun
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)"
# SPAWN_CLI_DIR override — force local source (used by e2e tests)
if [[ -n "${SPAWN_CLI_DIR:-}" && -f "$SPAWN_CLI_DIR/packages/cli/src/digitalocean/main.ts" ]]; then
_run_with_restart bun run "$SPAWN_CLI_DIR/packages/cli/src/digitalocean/main.ts" "$_AGENT_NAME" "$@"
exit $?
fi
# Local checkout — run from source
if [[ -n "$SCRIPT_DIR" && -f "$SCRIPT_DIR/../../packages/cli/src/digitalocean/main.ts" ]]; then
_run_with_restart bun run "$SCRIPT_DIR/../../packages/cli/src/digitalocean/main.ts" "$_AGENT_NAME" "$@"

View file

@ -62,6 +62,12 @@ _ensure_bun
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)"
# SPAWN_CLI_DIR override — force local source (used by e2e tests)
if [[ -n "${SPAWN_CLI_DIR:-}" && -f "$SPAWN_CLI_DIR/packages/cli/src/digitalocean/main.ts" ]]; then
_run_with_restart bun run "$SPAWN_CLI_DIR/packages/cli/src/digitalocean/main.ts" "$_AGENT_NAME" "$@"
exit $?
fi
# Local checkout — run from source
if [[ -n "$SCRIPT_DIR" && -f "$SCRIPT_DIR/../../packages/cli/src/digitalocean/main.ts" ]]; then
_run_with_restart bun run "$SCRIPT_DIR/../../packages/cli/src/digitalocean/main.ts" "$_AGENT_NAME" "$@"

View file

@ -62,6 +62,12 @@ _ensure_bun
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)"
# SPAWN_CLI_DIR override — force local source (used by e2e tests)
if [[ -n "${SPAWN_CLI_DIR:-}" && -f "$SPAWN_CLI_DIR/packages/cli/src/digitalocean/main.ts" ]]; then
_run_with_restart bun run "$SPAWN_CLI_DIR/packages/cli/src/digitalocean/main.ts" "$_AGENT_NAME" "$@"
exit $?
fi
# Local checkout — run from source
if [[ -n "$SCRIPT_DIR" && -f "$SCRIPT_DIR/../../packages/cli/src/digitalocean/main.ts" ]]; then
_run_with_restart bun run "$SCRIPT_DIR/../../packages/cli/src/digitalocean/main.ts" "$_AGENT_NAME" "$@"

View file

@ -62,6 +62,12 @@ _ensure_bun
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)"
# SPAWN_CLI_DIR override — force local source (used by e2e tests)
if [[ -n "${SPAWN_CLI_DIR:-}" && -f "$SPAWN_CLI_DIR/packages/cli/src/digitalocean/main.ts" ]]; then
_run_with_restart bun run "$SPAWN_CLI_DIR/packages/cli/src/digitalocean/main.ts" "$_AGENT_NAME" "$@"
exit $?
fi
# Local checkout — run from source
if [[ -n "$SCRIPT_DIR" && -f "$SCRIPT_DIR/../../packages/cli/src/digitalocean/main.ts" ]]; then
_run_with_restart bun run "$SCRIPT_DIR/../../packages/cli/src/digitalocean/main.ts" "$_AGENT_NAME" "$@"

View file

@ -62,6 +62,12 @@ _ensure_bun
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)"
# SPAWN_CLI_DIR override — force local source (used by e2e tests)
if [[ -n "${SPAWN_CLI_DIR:-}" && -f "$SPAWN_CLI_DIR/packages/cli/src/digitalocean/main.ts" ]]; then
_run_with_restart bun run "$SPAWN_CLI_DIR/packages/cli/src/digitalocean/main.ts" "$_AGENT_NAME" "$@"
exit $?
fi
# Local checkout — run from source
if [[ -n "$SCRIPT_DIR" && -f "$SCRIPT_DIR/../../packages/cli/src/digitalocean/main.ts" ]]; then
_run_with_restart bun run "$SCRIPT_DIR/../../packages/cli/src/digitalocean/main.ts" "$_AGENT_NAME" "$@"

View file

@ -15,6 +15,17 @@ set -eo pipefail
# Resolve script directory and source libraries
# ---------------------------------------------------------------------------
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# Auto-set SPAWN_CLI_DIR to repo root so shell scripts use local source instead
# of downloading pre-bundled .js from GitHub releases. Can be overridden by env.
if [ -z "${SPAWN_CLI_DIR:-}" ]; then
_repo_root="$(cd "${SCRIPT_DIR}/../.." && pwd)"
if [ -f "${_repo_root}/packages/cli/src/index.ts" ]; then
export SPAWN_CLI_DIR="${_repo_root}"
fi
unset _repo_root
fi
source "${SCRIPT_DIR}/lib/common.sh"
source "${SCRIPT_DIR}/lib/provision.sh"
source "${SCRIPT_DIR}/lib/verify.sh"

View file

@ -24,9 +24,14 @@ provision_agent() {
local stdout_file="${log_dir}/${app_name}.stdout"
local stderr_file="${log_dir}/${app_name}.stderr"
# Resolve CLI entry point (relative to this script's location in sh/e2e/lib/)
# Resolve CLI entry point
# SPAWN_CLI_DIR overrides auto-resolution — use this to force local source code
local cli_entry
cli_entry="$(cd "$(dirname "${BASH_SOURCE[0]}")/../../.." && pwd)/packages/cli/src/index.ts"
if [ -n "${SPAWN_CLI_DIR:-}" ]; then
cli_entry="${SPAWN_CLI_DIR}/packages/cli/src/index.ts"
else
cli_entry="$(cd "$(dirname "${BASH_SOURCE[0]}")/../../.." && pwd)/packages/cli/src/index.ts"
fi
if [ ! -f "${cli_entry}" ]; then
log_err "CLI entry point not found: ${cli_entry}"
@ -48,6 +53,9 @@ provision_agent() {
export SPAWN_NON_INTERACTIVE=1
export SPAWN_SKIP_GITHUB_AUTH=1
export SPAWN_SKIP_API_VALIDATION=1
export SPAWN_NO_UPDATE_CHECK=1
export BUN_RUNTIME_TRANSPILER_CACHE_PATH=0
export SPAWN_CLI_DIR="${SPAWN_CLI_DIR:-}"
export MODEL_ID="${MODEL_ID:-openrouter/auto}"
export OPENROUTER_API_KEY="${OPENROUTER_API_KEY}"

View file

@ -15,6 +15,11 @@ _ensure_bun
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)"
# SPAWN_CLI_DIR override — force local source (used by e2e tests)
if [[ -n "${SPAWN_CLI_DIR:-}" && -f "$SPAWN_CLI_DIR/packages/cli/src/gcp/main.ts" ]]; then
exec bun run "$SPAWN_CLI_DIR/packages/cli/src/gcp/main.ts" claude "$@"
fi
# Local checkout — run from source
if [[ -n "$SCRIPT_DIR" && -f "$SCRIPT_DIR/../../packages/cli/src/gcp/main.ts" ]]; then
exec bun run "$SCRIPT_DIR/../../packages/cli/src/gcp/main.ts" claude "$@"

View file

@ -15,6 +15,11 @@ _ensure_bun
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)"
# SPAWN_CLI_DIR override — force local source (used by e2e tests)
if [[ -n "${SPAWN_CLI_DIR:-}" && -f "$SPAWN_CLI_DIR/packages/cli/src/gcp/main.ts" ]]; then
exec bun run "$SPAWN_CLI_DIR/packages/cli/src/gcp/main.ts" codex "$@"
fi
# Local checkout — run from source
if [[ -n "$SCRIPT_DIR" && -f "$SCRIPT_DIR/../../packages/cli/src/gcp/main.ts" ]]; then
exec bun run "$SCRIPT_DIR/../../packages/cli/src/gcp/main.ts" codex "$@"

View file

@ -15,6 +15,11 @@ _ensure_bun
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)"
# SPAWN_CLI_DIR override — force local source (used by e2e tests)
if [[ -n "${SPAWN_CLI_DIR:-}" && -f "$SPAWN_CLI_DIR/packages/cli/src/gcp/main.ts" ]]; then
exec bun run "$SPAWN_CLI_DIR/packages/cli/src/gcp/main.ts" kilocode "$@"
fi
# Local checkout — run from source
if [[ -n "$SCRIPT_DIR" && -f "$SCRIPT_DIR/../../packages/cli/src/gcp/main.ts" ]]; then
exec bun run "$SCRIPT_DIR/../../packages/cli/src/gcp/main.ts" kilocode "$@"

View file

@ -15,6 +15,11 @@ _ensure_bun
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)"
# SPAWN_CLI_DIR override — force local source (used by e2e tests)
if [[ -n "${SPAWN_CLI_DIR:-}" && -f "$SPAWN_CLI_DIR/packages/cli/src/gcp/main.ts" ]]; then
exec bun run "$SPAWN_CLI_DIR/packages/cli/src/gcp/main.ts" openclaw "$@"
fi
# Local checkout — run from source
if [[ -n "$SCRIPT_DIR" && -f "$SCRIPT_DIR/../../packages/cli/src/gcp/main.ts" ]]; then
exec bun run "$SCRIPT_DIR/../../packages/cli/src/gcp/main.ts" openclaw "$@"

View file

@ -15,6 +15,11 @@ _ensure_bun
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)"
# SPAWN_CLI_DIR override — force local source (used by e2e tests)
if [[ -n "${SPAWN_CLI_DIR:-}" && -f "$SPAWN_CLI_DIR/packages/cli/src/gcp/main.ts" ]]; then
exec bun run "$SPAWN_CLI_DIR/packages/cli/src/gcp/main.ts" opencode "$@"
fi
# Local checkout — run from source
if [[ -n "$SCRIPT_DIR" && -f "$SCRIPT_DIR/../../packages/cli/src/gcp/main.ts" ]]; then
exec bun run "$SCRIPT_DIR/../../packages/cli/src/gcp/main.ts" opencode "$@"

View file

@ -15,6 +15,11 @@ _ensure_bun
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)"
# SPAWN_CLI_DIR override — force local source (used by e2e tests)
if [[ -n "${SPAWN_CLI_DIR:-}" && -f "$SPAWN_CLI_DIR/packages/cli/src/gcp/main.ts" ]]; then
exec bun run "$SPAWN_CLI_DIR/packages/cli/src/gcp/main.ts" zeroclaw "$@"
fi
# Local checkout — run from source
if [[ -n "$SCRIPT_DIR" && -f "$SCRIPT_DIR/../../packages/cli/src/gcp/main.ts" ]]; then
exec bun run "$SCRIPT_DIR/../../packages/cli/src/gcp/main.ts" zeroclaw "$@"

View file

@ -11,6 +11,12 @@ _ensure_bun() {
_ensure_bun
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)"
# SPAWN_CLI_DIR override — force local source (used by e2e tests)
if [[ -n "${SPAWN_CLI_DIR:-}" && -f "$SPAWN_CLI_DIR/packages/cli/src/hetzner/main.ts" ]]; then
exec bun run "$SPAWN_CLI_DIR/packages/cli/src/hetzner/main.ts" claude "$@"
fi
if [[ -n "$SCRIPT_DIR" && -f "$SCRIPT_DIR/../../packages/cli/src/hetzner/main.ts" ]]; then
exec bun run "$SCRIPT_DIR/../../packages/cli/src/hetzner/main.ts" claude "$@"
fi

View file

@ -11,6 +11,12 @@ _ensure_bun() {
_ensure_bun
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)"
# SPAWN_CLI_DIR override — force local source (used by e2e tests)
if [[ -n "${SPAWN_CLI_DIR:-}" && -f "$SPAWN_CLI_DIR/packages/cli/src/hetzner/main.ts" ]]; then
exec bun run "$SPAWN_CLI_DIR/packages/cli/src/hetzner/main.ts" codex "$@"
fi
if [[ -n "$SCRIPT_DIR" && -f "$SCRIPT_DIR/../../packages/cli/src/hetzner/main.ts" ]]; then
exec bun run "$SCRIPT_DIR/../../packages/cli/src/hetzner/main.ts" codex "$@"
fi

View file

@ -11,6 +11,12 @@ _ensure_bun() {
_ensure_bun
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)"
# SPAWN_CLI_DIR override — force local source (used by e2e tests)
if [[ -n "${SPAWN_CLI_DIR:-}" && -f "$SPAWN_CLI_DIR/packages/cli/src/hetzner/main.ts" ]]; then
exec bun run "$SPAWN_CLI_DIR/packages/cli/src/hetzner/main.ts" kilocode "$@"
fi
if [[ -n "$SCRIPT_DIR" && -f "$SCRIPT_DIR/../../packages/cli/src/hetzner/main.ts" ]]; then
exec bun run "$SCRIPT_DIR/../../packages/cli/src/hetzner/main.ts" kilocode "$@"
fi

View file

@ -11,6 +11,12 @@ _ensure_bun() {
_ensure_bun
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)"
# SPAWN_CLI_DIR override — force local source (used by e2e tests)
if [[ -n "${SPAWN_CLI_DIR:-}" && -f "$SPAWN_CLI_DIR/packages/cli/src/hetzner/main.ts" ]]; then
exec bun run "$SPAWN_CLI_DIR/packages/cli/src/hetzner/main.ts" openclaw "$@"
fi
if [[ -n "$SCRIPT_DIR" && -f "$SCRIPT_DIR/../../packages/cli/src/hetzner/main.ts" ]]; then
exec bun run "$SCRIPT_DIR/../../packages/cli/src/hetzner/main.ts" openclaw "$@"
fi

View file

@ -11,6 +11,12 @@ _ensure_bun() {
_ensure_bun
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)"
# SPAWN_CLI_DIR override — force local source (used by e2e tests)
if [[ -n "${SPAWN_CLI_DIR:-}" && -f "$SPAWN_CLI_DIR/packages/cli/src/hetzner/main.ts" ]]; then
exec bun run "$SPAWN_CLI_DIR/packages/cli/src/hetzner/main.ts" opencode "$@"
fi
if [[ -n "$SCRIPT_DIR" && -f "$SCRIPT_DIR/../../packages/cli/src/hetzner/main.ts" ]]; then
exec bun run "$SCRIPT_DIR/../../packages/cli/src/hetzner/main.ts" opencode "$@"
fi

View file

@ -11,6 +11,12 @@ _ensure_bun() {
_ensure_bun
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)"
# SPAWN_CLI_DIR override — force local source (used by e2e tests)
if [[ -n "${SPAWN_CLI_DIR:-}" && -f "$SPAWN_CLI_DIR/packages/cli/src/hetzner/main.ts" ]]; then
exec bun run "$SPAWN_CLI_DIR/packages/cli/src/hetzner/main.ts" zeroclaw "$@"
fi
if [[ -n "$SCRIPT_DIR" && -f "$SCRIPT_DIR/../../packages/cli/src/hetzner/main.ts" ]]; then
exec bun run "$SCRIPT_DIR/../../packages/cli/src/hetzner/main.ts" zeroclaw "$@"
fi

View file

@ -15,6 +15,11 @@ _ensure_bun
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)"
# SPAWN_CLI_DIR override — force local source (used by e2e tests)
if [[ -n "${SPAWN_CLI_DIR:-}" && -f "$SPAWN_CLI_DIR/packages/cli/src/sprite/main.ts" ]]; then
exec bun run "$SPAWN_CLI_DIR/packages/cli/src/sprite/main.ts" claude "$@"
fi
# Local checkout — run from source
if [[ -n "$SCRIPT_DIR" && -f "$SCRIPT_DIR/../../packages/cli/src/sprite/main.ts" ]]; then
exec bun run "$SCRIPT_DIR/../../packages/cli/src/sprite/main.ts" claude "$@"

View file

@ -15,6 +15,11 @@ _ensure_bun
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)"
# SPAWN_CLI_DIR override — force local source (used by e2e tests)
if [[ -n "${SPAWN_CLI_DIR:-}" && -f "$SPAWN_CLI_DIR/packages/cli/src/sprite/main.ts" ]]; then
exec bun run "$SPAWN_CLI_DIR/packages/cli/src/sprite/main.ts" codex "$@"
fi
# Local checkout — run from source
if [[ -n "$SCRIPT_DIR" && -f "$SCRIPT_DIR/../../packages/cli/src/sprite/main.ts" ]]; then
exec bun run "$SCRIPT_DIR/../../packages/cli/src/sprite/main.ts" codex "$@"

View file

@ -15,6 +15,11 @@ _ensure_bun
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)"
# SPAWN_CLI_DIR override — force local source (used by e2e tests)
if [[ -n "${SPAWN_CLI_DIR:-}" && -f "$SPAWN_CLI_DIR/packages/cli/src/sprite/main.ts" ]]; then
exec bun run "$SPAWN_CLI_DIR/packages/cli/src/sprite/main.ts" kilocode "$@"
fi
# Local checkout — run from source
if [[ -n "$SCRIPT_DIR" && -f "$SCRIPT_DIR/../../packages/cli/src/sprite/main.ts" ]]; then
exec bun run "$SCRIPT_DIR/../../packages/cli/src/sprite/main.ts" kilocode "$@"

View file

@ -15,6 +15,11 @@ _ensure_bun
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)"
# SPAWN_CLI_DIR override — force local source (used by e2e tests)
if [[ -n "${SPAWN_CLI_DIR:-}" && -f "$SPAWN_CLI_DIR/packages/cli/src/sprite/main.ts" ]]; then
exec bun run "$SPAWN_CLI_DIR/packages/cli/src/sprite/main.ts" openclaw "$@"
fi
# Local checkout — run from source
if [[ -n "$SCRIPT_DIR" && -f "$SCRIPT_DIR/../../packages/cli/src/sprite/main.ts" ]]; then
exec bun run "$SCRIPT_DIR/../../packages/cli/src/sprite/main.ts" openclaw "$@"

View file

@ -15,6 +15,11 @@ _ensure_bun
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)"
# SPAWN_CLI_DIR override — force local source (used by e2e tests)
if [[ -n "${SPAWN_CLI_DIR:-}" && -f "$SPAWN_CLI_DIR/packages/cli/src/sprite/main.ts" ]]; then
exec bun run "$SPAWN_CLI_DIR/packages/cli/src/sprite/main.ts" opencode "$@"
fi
# Local checkout — run from source
if [[ -n "$SCRIPT_DIR" && -f "$SCRIPT_DIR/../../packages/cli/src/sprite/main.ts" ]]; then
exec bun run "$SCRIPT_DIR/../../packages/cli/src/sprite/main.ts" opencode "$@"

View file

@ -15,6 +15,11 @@ _ensure_bun
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)"
# SPAWN_CLI_DIR override — force local source (used by e2e tests)
if [[ -n "${SPAWN_CLI_DIR:-}" && -f "$SPAWN_CLI_DIR/packages/cli/src/sprite/main.ts" ]]; then
exec bun run "$SPAWN_CLI_DIR/packages/cli/src/sprite/main.ts" zeroclaw "$@"
fi
# Local checkout — run from source
if [[ -n "$SCRIPT_DIR" && -f "$SCRIPT_DIR/../../packages/cli/src/sprite/main.ts" ]]; then
exec bun run "$SCRIPT_DIR/../../packages/cli/src/sprite/main.ts" zeroclaw "$@"