(opts: SetupOptions = {})
| 44 | } |
| 45 | |
| 46 | export async function runSetup(opts: SetupOptions = {}): Promise<void> { |
| 47 | const interactive = !opts.defaults && !opts.check && isInteractiveTTY(); |
| 48 | const promptOpts: PromptOptions = { interactive }; |
| 49 | |
| 50 | console.log(''); |
| 51 | console.log('QodeX setup — tune QodeX to your hardware and preferences.'); |
| 52 | if (interactive) { |
| 53 | console.log(`This will save to ${QODEX_CONFIG_FILE}. You can re-run anytime with \`qx setup\`.`); |
| 54 | } else if (opts.check) { |
| 55 | console.log('(--check mode: showing detected values, NOT writing config)'); |
| 56 | } else { |
| 57 | console.log('(--defaults / non-interactive mode: applying sensible defaults)'); |
| 58 | } |
| 59 | |
| 60 | // ── 1. Hardware ───────────────────────────────────────────────────────────── |
| 61 | section('[1/7] Detecting hardware'); |
| 62 | const hw = detectHardware(); |
| 63 | console.log(formatHardwareSummary(hw)); |
| 64 | |
| 65 | // ── 2. Primary model ──────────────────────────────────────────────────────── |
| 66 | section('[2/7] Primary model'); |
| 67 | paragraph( |
| 68 | 'The model that does the actual work. We just scanned your machine for what\'s\n' + |
| 69 | 'actually installed — those show up first. Cloud models need an API key.', |
| 70 | ); |
| 71 | |
| 72 | // Probe local backends (Ollama daemon + LM Studio server) for what's available |
| 73 | // RIGHT NOW. Detection is bounded (~1.5s per source) and silent on failure. |
| 74 | const detected = await detectAllLocalModels(); |
| 75 | if (detected.length > 0) { |
| 76 | // Group by source so the user can see backend distribution at a glance. |
| 77 | const byOllama = detected.filter(m => m.source === 'ollama'); |
| 78 | const byLmStudio = detected.filter(m => m.source === 'lm-studio'); |
| 79 | console.log(` Detected ${detected.length} local model${detected.length === 1 ? '' : 's'} across ${ |
| 80 | (byOllama.length > 0 ? 1 : 0) + (byLmStudio.length > 0 ? 1 : 0) |
| 81 | } backend${byOllama.length > 0 && byLmStudio.length > 0 ? 's' : ''}:`); |
| 82 | if (byLmStudio.length > 0) { |
| 83 | console.log(''); |
| 84 | console.log(' LM Studio (MLX-optimized for Apple Silicon, faster on M-series):'); |
| 85 | for (const m of byLmStudio) { |
| 86 | const f = formatModel(m); |
| 87 | console.log(` • ${f.label} ${f.hint}`); |
| 88 | } |
| 89 | } |
| 90 | if (byOllama.length > 0) { |
| 91 | console.log(''); |
| 92 | console.log(' Ollama (GGUF, broad compatibility, easier model management):'); |
| 93 | for (const m of byOllama) { |
| 94 | const f = formatModel(m); |
| 95 | console.log(` • ${f.label} ${f.hint}`); |
| 96 | } |
| 97 | } |
| 98 | if (byOllama.length > 0 && byLmStudio.length > 0) { |
| 99 | console.log(''); |
| 100 | console.log(' Two backends detected — real parallel sub-agents possible (one on each).'); |
| 101 | } |
| 102 | console.log(''); |
| 103 | } else { |
no test coverage detected