/** * ai-config.json — per-provider AI configuration. * * Structure: * { * "providers": { * "": { * "enabled": true, // terminal-native only * "keyRef": "keychain:ai:", // api only — pointer, never the key itself * "model": "...", // optional override * "baseUrl": "..." // optional override (api only) * } * }, * "defaults": { * "terminal": "claude-code", // default for Projects "Open in AI" * "chat": "anthropic" // default for Chat pane * } * } * * The JSON never contains raw API keys — only a `keyRef` pointer back into * the OS keychain under the `ai:` account name. This file is * safe to inspect, commit to a dotfiles repo, or share as a template. * * Migration: v0.x installs stored a single provider in ~/.claude_env (base * URL + model) plus a keychain slot named `ai-api-key`. On first read we * silently translate that into the new shape under whichever provider the * legacy base URL matches (or `anthropic` if empty). See migrateIfNeeded(). */ export interface ProviderConfig { enabled?: boolean; keyRef?: string; model?: string; baseUrl?: string; knownModels?: string[]; } export interface AiConfig { providers: Record; defaults: { terminal?: string; chat?: string; }; } export declare function readAiConfig(): AiConfig; /** * Atomic write — we stage to a temp file in the same directory so an * interrupted write doesn't leave a half-parsed JSON that the next read * interprets as "no config" and re-migrates. */ export declare function writeAiConfig(cfg: AiConfig): void; /** * Mutate helpers — useful for the CLI `ai` subcommands and the Config * panel's POST handlers. Always round-trip through readAiConfig() so we * pick up changes someone else made between invocations. */ export declare function setProviderEntry(id: string, entry: ProviderConfig | null): AiConfig; export declare function setDefault(kind: 'terminal' | 'chat', providerId: string | null): AiConfig; /** * One-shot migration from the v0.x single-provider layout. * * Source of truth for legacy state: * - ~/.claude_env → ANTHROPIC_BASE_URL + CLAUDE_MODEL * - keychain slot `ai-api-key` → the raw key * * We infer the provider-id from the base URL (empty = anthropic), copy * the key into the new slot `ai:`, and write the new ai-config.json * with that provider as defaults.chat. We intentionally do NOT delete the * old `ai-api-key` slot — if a user rolls back to an older nostr-station * release, they'd otherwise lose their key. The old slot is small and * inert; they can purge it manually when they're confident on the new * version. * * Also auto-adds `claude-code` as a terminal-native provider when the * `claude` binary is on PATH — most users installed it via onboard, so * a fresh migration lands in the "expected" two-surface state (Chat = * Anthropic API, Terminal = Claude Code). Absence is fine; they can add * it later via Config panel or `nostr-station ai add claude-code`. * * Returns { migrated: true } when we wrote a new file, false when * ai-config.json already existed and we left it alone. */ export declare function migrateIfNeeded(): Promise<{ migrated: boolean; from?: { provider: string; model?: string; }; terminalEnabled?: string[]; }>;