/** * Data layer for the first-run Config Wizard — no Ink, no React, so it can be * tested directly (the UI component imports it, tests import it too). */ import { DEFAULT_PROVIDERS } from '../shared/constants' import type { ModelInfo } from '../shared/types' /** Providers offered in the wizard's cloud path (Ollama has its own step). */ export const CLOUD_PROVIDERS = DEFAULT_PROVIDERS.filter( (p) => p.id !== 'ollama' && p.id !== 'mipham', ) export function getActiveModels(providerId: string): ModelInfo[] { const provider = DEFAULT_PROVIDERS.find((p) => p.id === providerId) return provider?.models.filter((m) => m.status === 'active') || [] } /** * Build the config.yml body written by the wizard. * * Built-in providers get **no** `models:` block on purpose: `mergeProviders` * (config/loader.ts) treats a supplied `models:` list as a wholesale * replacement of the built-in list, so writing bare `- id:` lines there would * strip `status` (→ the model picker shows "no active models"), * `contextWindow`, `maxOutput` and `vision` from every built-in model. * `models:` is written only for providers whose built-in list is empty * (Ollama), where it must carry every model field in full. */ export function buildConfigYaml( providerId: string, modelId: string, storedKey: string, ollamaModels: ModelInfo[] = [], ): string { const provider = DEFAULT_PROVIDERS.find((p) => p.id === providerId) const hasBuiltInModels = (provider?.models.length ?? 0) > 0 const lines = [ '# Mipham Code Configuration', `# Generated by Config Wizard — ${new Date().toISOString()}`, '', 'version: 1', `defaultProvider: ${providerId}`, `defaultModel: ${modelId}`, 'permission: default', '', 'providers:', ` - id: ${providerId}`, ` name: ${provider?.name || providerId}`, ` protocol: ${provider?.protocol || 'openai-compatible'}`, ...(provider?.baseUrl ? [` baseUrl: ${provider.baseUrl}`] : []), ` apiKey: ${storedKey}`, ] if (!hasBuiltInModels) { lines.push(' models:') for (const m of ollamaModels) { lines.push( ` - id: ${m.id}`, ` name: ${m.name}`, ` providerId: ${m.providerId}`, ` contextWindow: ${m.contextWindow}`, ` maxOutput: ${m.maxOutput}`, ` vision: ${m.vision}`, ` status: ${m.status}`, ) } } return lines.join('\n') }