diff --git a/src/cli.ts b/src/cli.ts index c23ab17..b4c689f 100755 --- a/src/cli.ts +++ b/src/cli.ts @@ -178,7 +178,7 @@ program spin.text = "Generating commit message" const gen = await vm.exec( worktreeAbs, - 'set -a; source ~/.env 2>/dev/null; set +a; git diff --staged | claude -p "write a short commit message summarizing these changes. output only the message, no quotes or extra text" > /tmp/sandlot_commit_msg', + 'git diff --staged | claude -p "write a short commit message summarizing these changes. output only the message, no quotes or extra text" > /tmp/sandlot_commit_msg', ) if (gen.exitCode !== 0) { spin.fail("Failed to generate commit message") diff --git a/src/vm.ts b/src/vm.ts index 19da88d..331ea0d 100644 --- a/src/vm.ts +++ b/src/vm.ts @@ -29,8 +29,16 @@ export async function ensure(): Promise { if (gitName) await $`limactl shell ${VM_NAME} -- git config --global user.name ${gitName}`.quiet() if (gitEmail) await $`limactl shell ${VM_NAME} -- git config --global user.email ${gitEmail}`.quiet() - // Replace ~/.claude and ~/.claude.json with symlinks to host credentials - await $`limactl shell ${VM_NAME} -- bash -c "rm -rf ~/.claude ~/.claude.json && ln -sf ${home}/.claude ~/.claude && ln -sf ${home}/.claude.json ~/.claude.json"`.quiet() + // Configure claude to use API key from host ~/.env (skip login prompt) + const helperScript = `#!/bin/sh\n. ${home}/.env 2>/dev/null\necho "$ANTHROPIC_API_KEY"\n` + const settingsJson = JSON.stringify({ apiKeyHelper: "~/.claude/api-key-helper.sh", skipDangerousModePermissionPrompt: true }) + const tmpHelper = `${home}/.sandlot-tmp-helper.sh` + const tmpSettings = `${home}/.sandlot-tmp-settings.json` + await Bun.write(tmpHelper, helperScript, { mode: 0o755 }) + await Bun.write(tmpSettings, settingsJson) + await $`limactl shell ${VM_NAME} -- bash -c "mkdir -p ~/.claude && cp ${tmpHelper} ~/.claude/api-key-helper.sh && chmod +x ~/.claude/api-key-helper.sh && cp ${tmpSettings} ~/.claude/settings.json"`.quiet() + await Bun.file(tmpHelper).delete() + await Bun.file(tmpSettings).delete() } /** Check VM status. */ @@ -52,23 +60,9 @@ export async function status(): Promise<"running" | "stopped" | "missing"> { return "missing" } -/** Load env vars from ~/.env */ -async function loadEnv(): Promise> { - const envFile = Bun.file(`${homedir()}/.env`) - if (!(await envFile.exists())) return {} - const vars: Record = {} - for (const line of (await envFile.text()).split("\n")) { - const match = line.match(/^([A-Z_]+)=(.+)$/) - if (match) vars[match[1]] = match[2] - } - return vars -} - /** Launch claude in the VM at the given workdir. */ export async function claude(workdir: string, prompt?: string): Promise { - const env = await loadEnv() - const envArgs = Object.entries(env).map(([k, v]) => `${k}=${v}`) - const args = ["limactl", "shell", `--workdir=${workdir}`, VM_NAME, "env", ...envArgs, "claude", "--dangerously-skip-permissions"] + const args = ["limactl", "shell", `--workdir=${workdir}`, VM_NAME, "claude", "--dangerously-skip-permissions"] if (prompt) args.push(prompt) const proc = Bun.spawn(args, { stdin: "inherit", stdout: "inherit", stderr: "inherit" }) await proc.exited