diff --git a/src/vm.ts b/src/vm.ts index 6e486a4..5a94d98 100644 --- a/src/vm.ts +++ b/src/vm.ts @@ -45,7 +45,10 @@ export async function create(log?: (msg: string) => void): Promise { // Create symlinks so git worktree absolute paths from the host resolve inside the container await $`container exec ${CONTAINER_NAME} bash -c ${`mkdir -p '${home}' && ln -s /host '${home}/dev' && ln -s /sandlot '${home}/.sandlot'`}`.quiet() - // Install Claude Code and configure (as ubuntu user) + // Install Bun and Claude Code (as ubuntu user) + log?.("Installing Bun") + await $`container exec --user ${USER} ${CONTAINER_NAME} bash -c ${"curl -fsSL https://bun.sh/install | bash"}`.quiet() + log?.("Installing Claude Code") await $`container exec --user ${USER} ${CONTAINER_NAME} bash -c ${"curl -fsSL https://claude.ai/install.sh | bash"}`.quiet() @@ -155,6 +158,7 @@ export async function claude(workdir: string, opts?: { prompt?: string; print?: `Your working directory is ${cwd}, a git worktree managed by sandlot.`, "The host's ~/dev is mounted read-only at /host.", "The host's ~/.sandlot is mounted at /sandlot.", + "Bun is installed at ~/.bun/bin/bun. Use bun instead of node/npm.", ] if (opts?.print) { systemPromptLines.push("IMPORTANT: Do not use plan mode. Do not call the EnterPlanMode tool. Proceed directly with the task.") @@ -162,7 +166,7 @@ export async function claude(workdir: string, opts?: { prompt?: string; print?: const systemPrompt = systemPromptLines.join("\n") const term = process.env.TERM || "xterm-256color" - const args = ["container", "exec", "-it", "--user", USER, "--workdir", cwd, CONTAINER_NAME, "env", `TERM=${term}`, 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=/home/${USER}/.bun/bin:/home/${USER}/.local/bin:/usr/local/bin:/usr/bin:/bin`, CLAUDE_BIN, "--dangerously-skip-permissions", "--model", "claude-opus-4-6", "--append-system-prompt", systemPrompt] if (opts?.print) args.push("-p", opts.print) else if (opts?.prompt) args.push(opts.prompt) @@ -197,7 +201,7 @@ export async function info(): Promise { /** Run a bash command in the container at the given workdir, capturing output. */ export async function exec(workdir: string, command: string): Promise<{ exitCode: number; stdout: string; stderr: string }> { - const result = await $`container exec --user ${USER} --workdir ${containerPath(workdir)} ${CONTAINER_NAME} bash -c ${"export PATH=$HOME/.local/bin:$PATH; " + command}`.nothrow().quiet() + const result = await $`container exec --user ${USER} --workdir ${containerPath(workdir)} ${CONTAINER_NAME} bash -c ${"export PATH=$HOME/.bun/bin:$HOME/.local/bin:$PATH; " + command}`.nothrow().quiet() return { exitCode: result.exitCode, stdout: result.stdout.toString().trim(),