diff --git a/src/cli.ts b/src/cli.ts index 440d35c..e7dde32 100755 --- a/src/cli.ts +++ b/src/cli.ts @@ -70,16 +70,55 @@ async function saveChanges(worktree: string, message?: string): Promise // ── sandlot new ────────────────────────────────────────────── -function branchFromPrompt(text: string): string { +function fallbackBranchName(text: string): string { return text .toLowerCase() .replace(/[^a-z0-9\s-]/g, "") .trim() .split(/\s+/) - .slice(0, 2) + .slice(0, 5) .join("-") } +async function branchFromPrompt(text: string): Promise { + // Read API key from ~/.env + const envFile = Bun.file(join(homedir(), ".env")) + if (!(await envFile.exists())) return fallbackBranchName(text) + + const envContent = await envFile.text() + const apiKey = envContent.match(/^(?:export\s+)?ANTHROPIC_API_KEY=["']?([^"'\s]+)["']?/m)?.[1] + if (!apiKey) return fallbackBranchName(text) + + try { + const res = await fetch("https://api.anthropic.com/v1/messages", { + method: "POST", + headers: { + "content-type": "application/json", + "x-api-key": apiKey, + "anthropic-version": "2023-06-01", + }, + body: JSON.stringify({ + model: "claude-haiku-4-5-20251001", + max_tokens: 30, + messages: [{ role: "user", content: `Generate a short git branch name (2-4 lowercase words, hyphen-separated, no slashes) for this task:\n\n${text}\n\nOutput ONLY the branch name, nothing else.` }], + }), + }) + + if (!res.ok) return fallbackBranchName(text) + + const body = await res.json() as any + const name = body.content?.[0]?.text?.trim() + .toLowerCase() + .replace(/[^a-z0-9-]/g, "-") + .replace(/-+/g, "-") + .replace(/^-|-$/g, "") + + return name && name.length > 0 && name.length <= 50 ? name : fallbackBranchName(text) + } catch { + return fallbackBranchName(text) + } +} + program .command("new") .argument("[branch]", "branch name or prompt (if it contains spaces)") @@ -90,14 +129,14 @@ program .action(async (branch: string | undefined, prompt: string | undefined, opts: { print?: string; save?: boolean }) => { // No branch given — derive from -p prompt if (!branch && opts.print) { - branch = branchFromPrompt(opts.print) + branch = await branchFromPrompt(opts.print) } else if (!branch) { console.error("✖ Branch name or prompt is required.") process.exit(1) } else if (branch.includes(" ")) { // If the "branch" contains spaces, it's actually a prompt — derive the branch name prompt = branch - branch = branchFromPrompt(branch) + branch = await branchFromPrompt(branch) } const root = await git.repoRoot() const worktreeAbs = join(homedir(), '.sandlot', basename(root), branch)