Files
peji 0f027e863b BMO: a living desktop buddy with a Claude brain
Standalone React + Vite app where BMO lives in a little garden:
- Redrawn avatar (src/avatar) with depth, cartoon controls and expressive
  faces; original bmo-preview avatar and scenery kept in src/bmo
- Idle life: wandering, chatter, boredom, sleep, pokes, weather and
  time-of-day reactions
- Chat via a local Node server streaming Claude replies (Haiku by default),
  with live scene awareness and tools to change color, outfit, sky,
  weather, move and perform
- Side menu for API key, appearance, environment and chat log

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 23:05:50 -04:00

40 lines
1.6 KiB
TypeScript

// 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);
}