no oauth
This commit is contained in:
parent
16d67fa3e7
commit
1d55cf427e
|
|
@ -6,7 +6,7 @@ import * as vm from "../vm.ts"
|
||||||
import * as state from "../state.ts"
|
import * as state from "../state.ts"
|
||||||
import { spinner } from "../spinner.ts"
|
import { spinner } from "../spinner.ts"
|
||||||
import { die } from "../fmt.ts"
|
import { die } from "../fmt.ts"
|
||||||
import { getApiKey } from "../env.ts"
|
import { requireApiKey } from "../env.ts"
|
||||||
import { renderMarkdown } from "../markdown.ts"
|
import { renderMarkdown } from "../markdown.ts"
|
||||||
import { saveChanges } from "./helpers.ts"
|
import { saveChanges } from "./helpers.ts"
|
||||||
|
|
||||||
|
|
@ -21,8 +21,7 @@ function fallbackBranchName(text: string): string {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function branchFromPrompt(text: string): Promise<string> {
|
async function branchFromPrompt(text: string): Promise<string> {
|
||||||
const apiKey = await getApiKey()
|
const apiKey = await requireApiKey()
|
||||||
if (!apiKey) return fallbackBranchName(text)
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const res = await fetch("https://api.anthropic.com/v1/messages", {
|
const res = await fetch("https://api.anthropic.com/v1/messages", {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import { homedir } from "os"
|
import { homedir } from "os"
|
||||||
import { join } from "path"
|
import { join } from "path"
|
||||||
|
import { die } from "./fmt.ts"
|
||||||
|
|
||||||
/** Read the ANTHROPIC_API_KEY from ~/.env. Returns undefined if not found. */
|
/** Read the ANTHROPIC_API_KEY from ~/.env. Returns undefined if not found. */
|
||||||
export async function getApiKey(): Promise<string | undefined> {
|
export async function getApiKey(): Promise<string | undefined> {
|
||||||
|
|
@ -9,3 +10,10 @@ export async function getApiKey(): Promise<string | undefined> {
|
||||||
const envContent = await envFile.text()
|
const envContent = await envFile.text()
|
||||||
return envContent.match(/^(?:export\s+)?ANTHROPIC_API_KEY=["']?([^"'\s]+)["']?/m)?.[1]
|
return envContent.match(/^(?:export\s+)?ANTHROPIC_API_KEY=["']?([^"'\s]+)["']?/m)?.[1]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Read the ANTHROPIC_API_KEY from ~/.env, dying if not found. */
|
||||||
|
export async function requireApiKey(): Promise<string> {
|
||||||
|
const key = await getApiKey()
|
||||||
|
if (!key) die("ANTHROPIC_API_KEY not found in ~/.env")
|
||||||
|
return key
|
||||||
|
}
|
||||||
|
|
|
||||||
29
src/vm.ts
29
src/vm.ts
|
|
@ -2,7 +2,7 @@ import { $ } from "bun"
|
||||||
import { existsSync } from "fs"
|
import { existsSync } from "fs"
|
||||||
import { homedir } from "os"
|
import { homedir } from "os"
|
||||||
import { dirname, join } from "path"
|
import { dirname, join } from "path"
|
||||||
import { getApiKey } from "./env.ts"
|
import { requireApiKey } from "./env.ts"
|
||||||
import { info } from "./fmt.ts"
|
import { info } from "./fmt.ts"
|
||||||
|
|
||||||
const DEBUG = !!process.env.DEBUG
|
const DEBUG = !!process.env.DEBUG
|
||||||
|
|
@ -145,35 +145,27 @@ async function installTooling(cached: boolean, log?: (msg: string) => void): Pro
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Configure git identity, API key helper, activity hook, and Claude settings. */
|
/** Configure git identity, API key helper, activity hook, and Claude settings. */
|
||||||
async function configureEnvironment(home: string, log?: (msg: string) => void, apiKey?: string): Promise<void> {
|
async function configureEnvironment(home: string, apiKey: string): Promise<void> {
|
||||||
const gitName = (await $`git config user.name`.quiet().text()).trim()
|
const gitName = (await $`git config user.name`.quiet().text()).trim()
|
||||||
const gitEmail = (await $`git config user.email`.quiet().text()).trim()
|
const gitEmail = (await $`git config user.email`.quiet().text()).trim()
|
||||||
if (gitName) await $`container exec --user ${USER} ${CONTAINER_NAME} git config --global user.name ${gitName}`.quiet()
|
if (gitName) await $`container exec --user ${USER} ${CONTAINER_NAME} git config --global user.name ${gitName}`.quiet()
|
||||||
if (gitEmail) await $`container exec --user ${USER} ${CONTAINER_NAME} git config --global user.email ${gitEmail}`.quiet()
|
if (gitEmail) await $`container exec --user ${USER} ${CONTAINER_NAME} git config --global user.email ${gitEmail}`.quiet()
|
||||||
|
|
||||||
if (!apiKey) {
|
|
||||||
log?.("Warning: ANTHROPIC_API_KEY not found in ~/.env — claude will require manual login")
|
|
||||||
}
|
|
||||||
|
|
||||||
const activityBin = `/home/${USER}/.local/bin/sandlot-activity`
|
const activityBin = `/home/${USER}/.local/bin/sandlot-activity`
|
||||||
const hooks = {
|
const hooks = {
|
||||||
UserPromptSubmit: [{ hooks: [{ type: "command", command: `${activityBin} active` }] }],
|
UserPromptSubmit: [{ hooks: [{ type: "command", command: `${activityBin} active` }] }],
|
||||||
Stop: [{ hooks: [{ type: "command", command: `${activityBin} idle` }] }],
|
Stop: [{ hooks: [{ type: "command", command: `${activityBin} idle` }] }],
|
||||||
}
|
}
|
||||||
const settingsJson = JSON.stringify(apiKey
|
const settingsJson = JSON.stringify({ apiKeyHelper: "~/.claude/api-key-helper.sh", skipDangerousModePermissionPrompt: true, hooks })
|
||||||
? { apiKeyHelper: "~/.claude/api-key-helper.sh", skipDangerousModePermissionPrompt: true, hooks }
|
|
||||||
: { skipDangerousModePermissionPrompt: true, hooks })
|
|
||||||
const claudeJson = JSON.stringify({ hasCompletedOnboarding: true, effortCalloutDismissed: true, projects: { "/": { hasTrustDialogAccepted: true } } })
|
const claudeJson = JSON.stringify({ hasCompletedOnboarding: true, effortCalloutDismissed: true, projects: { "/": { hasTrustDialogAccepted: true } } })
|
||||||
|
|
||||||
// Write the helper script to a temp file and copy it in so the key
|
// Write the helper script to a temp file and copy it in so the key
|
||||||
// never appears in a process argument visible in `ps`.
|
// never appears in a process argument visible in `ps`.
|
||||||
if (apiKey) {
|
const tmp = `${home}/.sandlot/.api-key-helper.tmp`
|
||||||
const tmp = `${home}/.sandlot/.api-key-helper.tmp`
|
await Bun.write(tmp, `#!/bin/sh\necho '${apiKey.replace(/'/g, "'\\''")}'\n`)
|
||||||
await Bun.write(tmp, `#!/bin/sh\necho '${apiKey.replace(/'/g, "'\\''")}'\n`)
|
await $`chmod +x ${tmp}`.quiet()
|
||||||
await $`chmod +x ${tmp}`.quiet()
|
await $`container exec --user ${USER} ${CONTAINER_NAME} bash -c ${"mkdir -p ~/.claude && cp /sandlot/.api-key-helper.tmp ~/.claude/api-key-helper.sh"}`.quiet()
|
||||||
await $`container exec --user ${USER} ${CONTAINER_NAME} bash -c ${"mkdir -p ~/.claude && cp /sandlot/.api-key-helper.tmp ~/.claude/api-key-helper.sh"}`.quiet()
|
await Bun.file(tmp).unlink()
|
||||||
await Bun.file(tmp).unlink()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Install activity tracking hook script
|
// Install activity tracking hook script
|
||||||
const activityTmp = `${home}/.sandlot/.sandlot-activity.tmp`
|
const activityTmp = `${home}/.sandlot/.sandlot-activity.tmp`
|
||||||
|
|
@ -199,6 +191,7 @@ echo '${claudeJson}' > ~/.claude.json
|
||||||
/** Create and provision the container from scratch. Fails if it already exists. */
|
/** Create and provision the container from scratch. Fails if it already exists. */
|
||||||
export async function create(log?: (msg: string) => void): Promise<void> {
|
export async function create(log?: (msg: string) => void): Promise<void> {
|
||||||
requireContainer()
|
requireContainer()
|
||||||
|
const apiKey = await requireApiKey()
|
||||||
|
|
||||||
const s = await status()
|
const s = await status()
|
||||||
if (s !== "missing") {
|
if (s !== "missing") {
|
||||||
|
|
@ -219,8 +212,7 @@ export async function create(log?: (msg: string) => void): Promise<void> {
|
||||||
await installTooling(cached, log)
|
await installTooling(cached, log)
|
||||||
|
|
||||||
log?.("Configuring environment")
|
log?.("Configuring environment")
|
||||||
const apiKey = await getApiKey()
|
await configureEnvironment(home, apiKey)
|
||||||
await configureEnvironment(home, log, apiKey)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Start a stopped container. */
|
/** Start a stopped container. */
|
||||||
|
|
@ -235,6 +227,7 @@ export async function start(): Promise<void> {
|
||||||
/** Ensure the sandlot container exists and is running. Creates and provisions on first use. */
|
/** Ensure the sandlot container exists and is running. Creates and provisions on first use. */
|
||||||
export async function ensure(log?: (msg: string) => void): Promise<void> {
|
export async function ensure(log?: (msg: string) => void): Promise<void> {
|
||||||
requireContainer()
|
requireContainer()
|
||||||
|
await requireApiKey()
|
||||||
|
|
||||||
// Ensure the container daemon is running (--enable-kernel-install skips interactive prompt)
|
// Ensure the container daemon is running (--enable-kernel-install skips interactive prompt)
|
||||||
if (DEBUG) await $`container system start --enable-kernel-install`.nothrow()
|
if (DEBUG) await $`container system start --enable-kernel-install`.nothrow()
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user