import { createSignal, onCleanup, createMemo } from "solid-js"; import { existsSync, readFileSync } from "fs"; import { homedir } from "os"; import { join } from "path"; // ── Config reader (no external deps) ─────────────────────────────────────── interface InfinicodeConfig { masterUrl: string; defaultModel: string; policy?: string; workerModels?: Record; cloudProviders?: Array<{ id: string; name: string; enabled: boolean; apiKey?: string }>; } function findConfigPath(): string { const home = homedir(); const paths = [ // Windows — Conf appends "-nodejs" for Node projects join(home, "AppData", "Roaming", "infinicode-nodejs", "Config", "config.json"), join(home, "AppData", "Roaming", "infinicode", "Config", "config.json"), // Linux join(home, ".config", "infinicode", "config.json"), // macOS join(home, "Library", "Preferences", "infinicode", "config.json"), ]; for (const p of paths) { if (existsSync(p)) return p; } return paths[0]; } function loadConfig(): InfinicodeConfig | null { try { const path = findConfigPath(); if (!existsSync(path)) return null; return JSON.parse(readFileSync(path, "utf-8")) as InfinicodeConfig; } catch { return null; } } // ── Routing info ─────────────────────────────────────────────────────────── // Every policy auto-routes across providers except `offline`, which is locked // to the local machine — mirrors the kernel router's one locked mode. const LOCKED_POLICIES = new Set(["offline"]); interface RoutingBadge { glyph: string; text: string; /** true = actively auto-routing (drives the pulse highlight). */ active: boolean; } function buildRoutingBadge(cfg: InfinicodeConfig | null, tuiModel?: string): RoutingBadge { if (!cfg) return { glyph: "◆", text: "AUTO (no config)", active: true }; const enabledCloud = (cfg.cloudProviders ?? []).filter((p) => p.enabled && p.apiKey); const providerCount = 1 + enabledCloud.length; // ollama + cloud const pinned = Object.keys(cfg.workerModels ?? {}).length; const policy = cfg.policy ?? "balanced"; const codingPin = cfg.workerModels?.["coding"]; const autoModel = codingPin ? `${codingPin.providerId}/${codingPin.modelId}` : `ollama/${cfg.defaultModel}`; // If the user manually pinned a model in the TUI, that overrides routing. if (tuiModel && tuiModel !== autoModel) { const [prov, ...rest] = tuiModel.split("/"); return { glyph: "◇", text: `SINGLE ${prov}/${rest.join("/")}`, active: false }; } // The one locked mode: offline stays local-only. if (LOCKED_POLICIES.has(policy)) { return { glyph: "🔒", text: `LOCKED ${policy} (local only)`, active: false }; } return { glyph: "◆", text: `AUTO policy=${policy} providers=${providerCount} pins=${pinned}`, active: true, }; } // ── Plugin ────────────────────────────────────────────────────────────────── const tui = async (api: any) => { const [cfg] = createSignal(loadConfig()); const getTuiModel = (): string | undefined => { try { return api.state?.config?.model; } catch { return undefined; } }; const [tuiModel, setTuiModel] = createSignal(getTuiModel()); if (api.event?.on) { const unsub = api.event.on("session.next.model_switched", () => { setTuiModel(getTuiModel()); }); onCleanup(unsub); } const badge = createMemo(() => buildRoutingBadge(cfg(), tuiModel())); // Pulse the highlight color while auto-routing is active so the badge reads // as "live". Static gold when locked / single-pinned. const PULSE = ["#FFD86B", "#FFE9A6", "#F5C542"]; const [pulse, setPulse] = createSignal(0); const timer = setInterval(() => setPulse((i) => (i + 1) % PULSE.length), 600); onCleanup(() => clearInterval(timer)); const color = () => (badge().active ? PULSE[pulse()] : "#FFD86B"); const render = () => ( {`${badge().glyph} ${badge().text}`} ); api.slots.register({ slots: { // Right of the home prompt — routing badge home_prompt_right() { return render(); }, // Right of the session prompt — routing badge session_prompt_right(props: { session_id: string }) { return render(); }, }, }); }; // The TUI plugin loader reads `mod.default` (strict mode) and requires an object // with a tui() function — a bare `export const tui` is silently skipped. export default { id: "infinicode-routing-mode", tui };