Refactor tooling install steps and extract PATH constant

This commit is contained in:
Chris Wanstrath 2026-02-21 08:45:32 -08:00
parent ca7af3d671
commit 417bb666b2

View File

@ -6,6 +6,7 @@ import { getApiKey } from "./env.ts"
const CONTAINER_NAME = "sandlot" const CONTAINER_NAME = "sandlot"
const USER = "ubuntu" const USER = "ubuntu"
const CLAUDE_BIN = `/home/${USER}/.local/bin/claude` const CLAUDE_BIN = `/home/${USER}/.local/bin/claude`
const CONTAINER_PATH = `/home/${USER}/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin`
/** Translate a host path to its corresponding container path. */ /** Translate a host path to its corresponding container path. */
export function containerPath(hostPath: string): string { export function containerPath(hostPath: string): string {
@ -74,11 +75,20 @@ async function hasCachedTooling(): Promise<boolean> {
/** Install Bun, Claude Code, neofetch, and Neovim using cached binaries when available. */ /** Install Bun, Claude Code, neofetch, and Neovim using cached binaries when available. */
async function installTooling(cached: boolean, log?: (msg: string) => void): Promise<void> { async function installTooling(cached: boolean, log?: (msg: string) => void): Promise<void> {
// Ensure cache directory exists on the host (mounted at /sandlot/.cache in the container)
await $`mkdir -p ${CACHE_DIR}`.quiet()
if (cached) { if (cached) {
log?.("Installing packages (cached)") log?.("Installing packages (cached)")
await run( await run(
$`container exec --user ${USER} ${CONTAINER_NAME} bash -c ${"mkdir -p ~/.local/bin && cp /sandlot/.cache/bun /sandlot/.cache/claude /sandlot/.cache/neofetch ~/.local/bin/ && chmod +x ~/.local/bin/bun ~/.local/bin/claude ~/.local/bin/neofetch && ln -sf bun ~/.local/bin/bunx && tar xzf /sandlot/.cache/nvim.tar.gz -C ~/.local --strip-components=1"}`, $`container exec --user ${USER} ${CONTAINER_NAME} bash -c ${"mkdir -p ~/.local/bin"}`,
"Install from cache") "Create bin directory")
await run(
$`container exec --user ${USER} ${CONTAINER_NAME} bash -c ${"cp /sandlot/.cache/bun /sandlot/.cache/claude /sandlot/.cache/neofetch ~/.local/bin/ && chmod +x ~/.local/bin/bun ~/.local/bin/claude ~/.local/bin/neofetch && ln -sf bun ~/.local/bin/bunx"}`,
"Install cached binaries")
await run(
$`container exec --user ${USER} ${CONTAINER_NAME} bash -c ${"tar xzf /sandlot/.cache/nvim.tar.gz -C ~/.local --strip-components=1"}`,
"Install cached Neovim")
return return
} }
@ -99,11 +109,11 @@ async function installTooling(cached: boolean, log?: (msg: string) => void): Pro
log?.("Installing Neovim") log?.("Installing Neovim")
await run( await run(
$`container exec --user ${USER} ${CONTAINER_NAME} bash -c ${"curl -fsSL https://github.com/neovim/neovim/releases/latest/download/nvim-linux-arm64.tar.gz -o /sandlot/.cache/nvim.tar.gz && tar xzf /sandlot/.cache/nvim.tar.gz -C ~/.local --strip-components=1"}`, $`container exec --user ${USER} ${CONTAINER_NAME} bash -c ${"curl -fsSL https://github.com/neovim/neovim/releases/latest/download/nvim-linux-arm64.tar.gz -o /tmp/nvim.tar.gz && tar xzf /tmp/nvim.tar.gz -C ~/.local --strip-components=1"}`,
"Neovim installation") "Neovim installation")
// Cache binaries for next time // Cache binaries for next time
await $`container exec --user ${USER} ${CONTAINER_NAME} bash -c ${"cp ~/.local/bin/bun ~/.local/bin/claude ~/.local/bin/neofetch /sandlot/.cache/"}`.nothrow().quiet() await $`container exec --user ${USER} ${CONTAINER_NAME} bash -c ${"cp ~/.local/bin/bun ~/.local/bin/claude ~/.local/bin/neofetch /sandlot/.cache/ && cp /tmp/nvim.tar.gz /sandlot/.cache/nvim.tar.gz"}`.nothrow().quiet()
} }
/** Configure git identity, API key helper, activity hook, and Claude settings. */ /** Configure git identity, API key helper, activity hook, and Claude settings. */
@ -242,7 +252,7 @@ export async function claude(workdir: string, opts?: { prompt?: string; print?:
const systemPrompt = systemPromptLines.join("\n") const systemPrompt = systemPromptLines.join("\n")
const term = process.env.TERM || "xterm-256color" const term = process.env.TERM || "xterm-256color"
const args = ["container", "exec", "-it", "--user", USER, "--workdir", cwd, CONTAINER_NAME, "env", `TERM=${term}`, `PATH=/home/${USER}/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin`, CLAUDE_BIN, "--dangerously-skip-permissions", "--model", "claude-opus-4-6", "--append-system-prompt", systemPrompt] const args = ["container", "exec", "-it", "--user", USER, "--workdir", cwd, CONTAINER_NAME, "env", `TERM=${term}`, `PATH=${CONTAINER_PATH}`, CLAUDE_BIN, "--dangerously-skip-permissions", "--model", "claude-opus-4-6", "--append-system-prompt", systemPrompt]
if (opts?.continue) args.push("--continue") if (opts?.continue) args.push("--continue")
if (opts?.print) args.push("-p", opts.print) if (opts?.print) args.push("-p", opts.print)
else if (opts?.prompt) args.push(opts.prompt) else if (opts?.prompt) args.push(opts.prompt)
@ -262,7 +272,7 @@ export async function claude(workdir: string, opts?: { prompt?: string; print?:
export async function shell(workdir?: string): Promise<void> { export async function shell(workdir?: string): Promise<void> {
const args = ["container", "exec", "-it", "--user", USER] const args = ["container", "exec", "-it", "--user", USER]
if (workdir) args.push("--workdir", containerPath(workdir)) if (workdir) args.push("--workdir", containerPath(workdir))
args.push(CONTAINER_NAME, "env", "TERM=xterm-256color", `PATH=/home/${USER}/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin`, "fish", "--login") args.push(CONTAINER_NAME, "env", "TERM=xterm-256color", `PATH=${CONTAINER_PATH}`, "fish", "--login")
const proc = Bun.spawn(args, { stdin: "inherit", stdout: "inherit", stderr: "inherit" }) const proc = Bun.spawn(args, { stdin: "inherit", stdout: "inherit", stderr: "inherit" })
await proc.exited await proc.exited
} }
@ -270,7 +280,7 @@ export async function shell(workdir?: string): Promise<void> {
/** Run neofetch in the container. */ /** Run neofetch in the container. */
export async function info(): Promise<void> { export async function info(): Promise<void> {
const proc = Bun.spawn( const proc = Bun.spawn(
["container", "exec", "--user", USER, CONTAINER_NAME, "env", `PATH=/home/${USER}/.local/bin:/usr/bin:/bin`, "neofetch"], ["container", "exec", "--user", USER, CONTAINER_NAME, "env", `PATH=${CONTAINER_PATH}`, "neofetch"],
{ stdin: "inherit", stdout: "inherit", stderr: "inherit" }, { stdin: "inherit", stdout: "inherit", stderr: "inherit" },
) )
await proc.exited await proc.exited