// Saves the Anthropic API key the user pastes into the side menu. The key is // written to the project's .env (gitignored, owner-only permissions) so it // survives restarts, and applied to process.env right away. It is never sent // back to the browser — only a masked hint is. import { chmodSync, existsSync, readFileSync, writeFileSync } from "node:fs"; import path from "node:path"; import { fileURLToPath } from "node:url"; const here = path.dirname(fileURLToPath(import.meta.url)); export const ENV_PATH = path.resolve(here, "../.env"); const KEY_LINE = /^\s*ANTHROPIC_API_KEY\s*=.*$/m; export function currentKey(): string | undefined { return process.env.ANTHROPIC_API_KEY?.trim() || undefined; } export function keyHint(key = currentKey()): string | null { if (!key) return null; return `${key.slice(0, 7)}…${key.slice(-4)}`; } /** Writes (or with `null`, clears) ANTHROPIC_API_KEY in .env and process.env. */ export function storeKey(key: string | null) { const existing = existsSync(ENV_PATH) ? readFileSync(ENV_PATH, "utf8") : ""; const line = `ANTHROPIC_API_KEY=${key ?? ""}`; let next = KEY_LINE.test(existing) ? existing.replace(KEY_LINE, line) : `${line}\n${existing}`; if (!next.endsWith("\n")) next += "\n"; writeFileSync(ENV_PATH, next, { mode: 0o600 }); chmodSync(ENV_PATH, 0o600); if (key) process.env.ANTHROPIC_API_KEY = key; else delete process.env.ANTHROPIC_API_KEY; } /** Rough shape check so obvious paste mistakes get a friendly error. */ export function looksLikeKey(key: string) { return /^sk-ant-[A-Za-z0-9_-]{20,}$/.test(key); }