From 16c8a2b90b7e9c23dff94b0080f61eccd0a2a091 Mon Sep 17 00:00:00 2001 From: A <258483684+la14-1@users.noreply.github.com> Date: Sun, 22 Feb 2026 19:27:21 -0800 Subject: [PATCH] fix: use getSpawnDir()/getConnectionPath() in all cloud providers (#1774) Fixes #1769 All 8 cloud providers hard-coded `${process.env.HOME}/.spawn` for connection data, bypassing the SPAWN_HOME env var support in history.ts. Replaced all 16 occurrences with getSpawnDir() and getConnectionPath(). Co-authored-by: Claude Co-authored-by: Claude Opus 4.6 (1M context) --- cli/package.json | 2 +- cli/src/aws/aws.ts | 5 +++-- cli/src/daytona/daytona.ts | 5 +++-- cli/src/digitalocean/digitalocean.ts | 5 +++-- cli/src/fly/fly.ts | 5 +++-- cli/src/gcp/gcp.ts | 5 +++-- cli/src/hetzner/hetzner.ts | 5 +++-- cli/src/local/local.ts | 5 +++-- cli/src/sprite/sprite.ts | 5 +++-- 9 files changed, 25 insertions(+), 17 deletions(-) diff --git a/cli/package.json b/cli/package.json index 631e267d..07dd1b75 100644 --- a/cli/package.json +++ b/cli/package.json @@ -1,6 +1,6 @@ { "name": "@openrouter/spawn", - "version": "0.7.1", + "version": "0.7.2", "type": "module", "bin": { "spawn": "cli.js" diff --git a/cli/src/aws/aws.ts b/cli/src/aws/aws.ts index c220e9d8..da5a7fd2 100644 --- a/cli/src/aws/aws.ts +++ b/cli/src/aws/aws.ts @@ -21,6 +21,7 @@ import { getPackagesForTier, needsNode, needsBun, NODE_INSTALL_CMD } from "../sh import { SSH_BASE_OPTS, sleep, waitForSsh as sharedWaitForSsh } from "../shared/ssh"; import * as v from "valibot"; import { parseJsonWith } from "../shared/parse"; +import { getSpawnDir, getConnectionPath } from "../history.js"; const DASHBOARD_URL = "https://lightsail.aws.amazon.com/"; @@ -863,7 +864,7 @@ export async function waitForInstance(maxAttempts = 60): Promise { // ─── Connection Tracking ──────────────────────────────────────────────────── function saveVmConnection(ip: string, user: string, serverId: string, serverName: string, cloud: string): void { - const dir = `${process.env.HOME}/.spawn`; + const dir = getSpawnDir(); mkdirSync(dir, { recursive: true, }); @@ -884,7 +885,7 @@ function saveVmConnection(ip: string, user: string, serverId: string, serverName } export function saveLaunchCmd(launchCmd: string): void { - const connFile = `${process.env.HOME}/.spawn/last-connection.json`; + const connFile = getConnectionPath(); try { const data = JSON.parse(readFileSync(connFile, "utf-8")); data.launch_cmd = launchCmd; diff --git a/cli/src/daytona/daytona.ts b/cli/src/daytona/daytona.ts index f1efde70..5579a9ea 100644 --- a/cli/src/daytona/daytona.ts +++ b/cli/src/daytona/daytona.ts @@ -18,6 +18,7 @@ import type { CloudInitTier } from "../shared/agents"; import { getPackagesForTier, needsNode, needsBun, NODE_INSTALL_CMD } from "../shared/cloud-init"; import { parseJsonWith, parseJsonRaw } from "../shared/parse"; import * as v from "valibot"; +import { getSpawnDir, getConnectionPath } from "../history.js"; const DAYTONA_API_BASE = "https://app.daytona.io/api"; const DAYTONA_DASHBOARD_URL = "https://app.daytona.io/"; @@ -220,7 +221,7 @@ function saveVmConnection( cloud: string, launchCmd?: string, ): void { - const dir = `${process.env.HOME}/.spawn`; + const dir = getSpawnDir(); mkdirSync(dir, { recursive: true, }); @@ -244,7 +245,7 @@ function saveVmConnection( } export function saveLaunchCmd(launchCmd: string): void { - const connFile = `${process.env.HOME}/.spawn/last-connection.json`; + const connFile = getConnectionPath(); try { const data = JSON.parse(readFileSync(connFile, "utf-8")); data.launch_cmd = launchCmd; diff --git a/cli/src/digitalocean/digitalocean.ts b/cli/src/digitalocean/digitalocean.ts index 5b247eb2..494a112d 100644 --- a/cli/src/digitalocean/digitalocean.ts +++ b/cli/src/digitalocean/digitalocean.ts @@ -20,6 +20,7 @@ import type { CloudInitTier } from "../shared/agents"; import { getPackagesForTier, needsNode, needsBun, NODE_INSTALL_CMD } from "../shared/cloud-init"; import { parseJsonWith } from "../shared/parse"; import { SSH_BASE_OPTS, sleep, waitForSsh as sharedWaitForSsh } from "../shared/ssh"; +import { getSpawnDir, getConnectionPath } from "../history.js"; const DO_API_BASE = "https://api.digitalocean.com/v2"; const DO_DASHBOARD_URL = "https://cloud.digitalocean.com/droplets"; @@ -696,7 +697,7 @@ function saveVmConnection( cloud: string, launchCmd?: string, ): void { - const dir = `${process.env.HOME}/.spawn`; + const dir = getSpawnDir(); mkdirSync(dir, { recursive: true, }); @@ -720,7 +721,7 @@ function saveVmConnection( } export function saveLaunchCmd(launchCmd: string): void { - const connFile = `${process.env.HOME}/.spawn/last-connection.json`; + const connFile = getConnectionPath(); try { const data = JSON.parse(readFileSync(connFile, "utf-8")); data.launch_cmd = launchCmd; diff --git a/cli/src/fly/fly.ts b/cli/src/fly/fly.ts index e45c7f03..b12d1c40 100644 --- a/cli/src/fly/fly.ts +++ b/cli/src/fly/fly.ts @@ -20,6 +20,7 @@ import type { CloudInitTier } from "../shared/agents"; import { getPackagesForTier, needsNode, needsBun, NODE_INSTALL_CMD } from "../shared/cloud-init"; import * as v from "valibot"; import { parseJsonWith, parseJsonRaw } from "../shared/parse"; +import { getSpawnDir, getConnectionPath } from "../history.js"; const FLY_API_BASE = "https://api.machines.dev/v1"; const FLY_DASHBOARD_URL = "https://fly.io/dashboard"; @@ -325,7 +326,7 @@ export function saveVmConnection( cloud: string, launchCmd?: string, ): void { - const dir = `${process.env.HOME}/.spawn`; + const dir = getSpawnDir(); mkdirSync(dir, { recursive: true, }); @@ -350,7 +351,7 @@ export function saveVmConnection( /** Append launch_cmd to the last-connection.json file */ export function saveLaunchCmd(launchCmd: string): void { - const connFile = `${process.env.HOME}/.spawn/last-connection.json`; + const connFile = getConnectionPath(); try { const data = JSON.parse(readFileSync(connFile, "utf-8")); data.launch_cmd = launchCmd; diff --git a/cli/src/gcp/gcp.ts b/cli/src/gcp/gcp.ts index a7c8a17b..6e3c0100 100644 --- a/cli/src/gcp/gcp.ts +++ b/cli/src/gcp/gcp.ts @@ -18,6 +18,7 @@ import { import type { CloudInitTier } from "../shared/agents"; import { getPackagesForTier, needsNode, needsBun, NODE_INSTALL_CMD } from "../shared/cloud-init"; import { SSH_BASE_OPTS, sleep, waitForSsh as sharedWaitForSsh } from "../shared/ssh"; +import { getSpawnDir, getConnectionPath } from "../history.js"; const DASHBOARD_URL = "https://console.cloud.google.com/compute/instances"; @@ -750,7 +751,7 @@ export async function createInstance( logInfo(`Instance created: IP=${gcpServerIp}`); // Save connection info - const dir = `${process.env.HOME}/.spawn`; + const dir = getSpawnDir(); mkdirSync(dir, { recursive: true, }); @@ -1007,7 +1008,7 @@ export async function destroyInstance(name?: string): Promise { // ─── Connection Tracking ──────────────────────────────────────────────────── export function saveLaunchCmd(launchCmd: string): void { - const connFile = `${process.env.HOME}/.spawn/last-connection.json`; + const connFile = getConnectionPath(); try { const data = JSON.parse(readFileSync(connFile, "utf-8")); data.launch_cmd = launchCmd; diff --git a/cli/src/hetzner/hetzner.ts b/cli/src/hetzner/hetzner.ts index ac35fae4..9992923a 100644 --- a/cli/src/hetzner/hetzner.ts +++ b/cli/src/hetzner/hetzner.ts @@ -20,6 +20,7 @@ import { getPackagesForTier, needsNode, needsBun, NODE_INSTALL_CMD } from "../sh import { SSH_BASE_OPTS, sleep, waitForSsh as sharedWaitForSsh } from "../shared/ssh"; import * as v from "valibot"; import { parseJsonWith } from "../shared/parse"; +import { getSpawnDir, getConnectionPath } from "../history.js"; const HETZNER_API_BASE = "https://api.hetzner.cloud/v1"; const HETZNER_DASHBOARD_URL = "https://console.hetzner.cloud/"; @@ -339,7 +340,7 @@ export function saveVmConnection( cloud: string, launchCmd?: string, ): void { - const dir = `${process.env.HOME}/.spawn`; + const dir = getSpawnDir(); mkdirSync(dir, { recursive: true, }); @@ -363,7 +364,7 @@ export function saveVmConnection( } export function saveLaunchCmd(launchCmd: string): void { - const connFile = `${process.env.HOME}/.spawn/last-connection.json`; + const connFile = getConnectionPath(); try { const data = JSON.parse(readFileSync(connFile, "utf-8")); data.launch_cmd = launchCmd; diff --git a/cli/src/local/local.ts b/cli/src/local/local.ts index e9e5267a..ad159bb0 100644 --- a/cli/src/local/local.ts +++ b/cli/src/local/local.ts @@ -3,6 +3,7 @@ import { copyFileSync, mkdirSync, readFileSync } from "node:fs"; import { dirname } from "node:path"; import { spawn } from "node:child_process"; +import { getSpawnDir, getConnectionPath } from "../history.js"; // ─── Execution ─────────────────────────────────────────────────────────────── @@ -82,7 +83,7 @@ export async function interactiveSession(cmd: string): Promise { // ─── Connection Tracking ───────────────────────────────────────────────────── export function saveLocalConnection(): void { - const dir = `${process.env.HOME}/.spawn`; + const dir = getSpawnDir(); mkdirSync(dir, { recursive: true, }); @@ -111,7 +112,7 @@ export function saveLocalConnection(): void { /** Save launch command to the last-connection.json file. */ export function saveLaunchCmd(launchCmd: string): void { - const connFile = `${process.env.HOME}/.spawn/last-connection.json`; + const connFile = getConnectionPath(); try { const data = JSON.parse(readFileSync(connFile, "utf-8")); data.launch_cmd = launchCmd; diff --git a/cli/src/sprite/sprite.ts b/cli/src/sprite/sprite.ts index b0a3e53e..5936558e 100644 --- a/cli/src/sprite/sprite.ts +++ b/cli/src/sprite/sprite.ts @@ -13,6 +13,7 @@ import { defaultSpawnName, } from "../shared/ui"; import { sleep } from "../shared/ssh"; +import { getSpawnDir, getConnectionPath } from "../history.js"; // ─── Configurable Constants ────────────────────────────────────────────────── @@ -426,7 +427,7 @@ export async function setupShellEnvironment(): Promise { // ─── Connection Tracking ───────────────────────────────────────────────────── export function saveVmConnection(): void { - const dir = `${process.env.HOME}/.spawn`; + const dir = getSpawnDir(); mkdirSync(dir, { recursive: true, }); @@ -440,7 +441,7 @@ export function saveVmConnection(): void { } export function saveLaunchCmd(launchCmd: string): void { - const connFile = `${process.env.HOME}/.spawn/last-connection.json`; + const connFile = getConnectionPath(); try { const data = JSON.parse(readFileSync(connFile, "utf-8")); data.launch_cmd = launchCmd;