import { testRender } from "@opentui/solid" import type { AgentInfo, ModelInfo, SessionInfo } from "@opencode/client" import path from "node:path" import { ConfigProvider } from "../../src/config" import { ArgsProvider, type Args } from "../../src/context/args" import { ClientProvider } from "../../src/context/client" import { DataProvider, useData } from "../../src/context/data" import { LocalProvider, useLocal } from "../../src/context/local" import { Keymap } from "../../src/context/keymap" import { LocationProvider, useLocation } from "../../src/context/location" import { PermissionProvider } from "../../src/context/permission" import { RouteProvider, useRoute } from "../../src/context/route" import { ThemeProvider } from "../../src/context/theme" import { ToastProvider } from "../../src/ui/toast" import { DialogProvider, useDialog } from "../../src/ui/dialog" import type { ModelPreference } from "../../src/model-preference" import { tmpdir } from "./fixture" import { createApi, createEventStream, createFetch, directory, json, type FetchHandler } from "./tui-client" import { TestTuiContexts } from "./tui-environment" import { createTuiResolvedConfig } from "./tui-runtime" export async function renderLocal( input: { models?: ModelInfo[] agents?: AgentInfo[] sessions?: SessionInfo[] preferences?: Partial args?: Args fetch?: FetchHandler } = {}, ) { const temporary = await tmpdir() await Bun.write(path.join(temporary.path, "model.json"), JSON.stringify(input.preferences ?? {})) const events = createEventStream() const calls = createFetch(async (url, request) => { const response = await input.fetch?.(url, request) if (response) return response const location = { directory: url.searchParams.get("location[directory]") ?? directory } if (url.pathname === "/api/agent") return json({ location, data: input.agents ?? [agent("build")] }) if (url.pathname === "/api/model") return json({ location, data: input.models ?? [model("first")] }) const session = input.sessions?.find((session) => url.pathname === `/api/session/${session.id}`) if (session) return json({ data: session }) }, events) let local!: ReturnType let route!: ReturnType let data!: ReturnType let location!: ReturnType let dialog!: ReturnType function Probe() { local = useLocal() route = useRoute() data = useData() location = useLocation() dialog = useDialog() return } const setup = await testRender( () => ( ({}) }}> ), { width: 100, height: 30, kittyKeyboard: true }, ) await waitForModel(() => local !== undefined && local.model.ready) await data.location.sync() return { ...setup, local, route, data, location, dialog, events, state: temporary.path, async [Symbol.asyncDispose]() { setup.renderer.destroy() await temporary[Symbol.asyncDispose]() }, } } async function waitForModel(ready: () => boolean) { const started = Date.now() while (!ready()) { if (Date.now() - started > 2_000) throw new Error("Timed out waiting for local model data") await Bun.sleep(10) } } export function model(id: string, variants: string[] = []): ModelInfo { return { id, modelID: id, providerID: "provider", name: id, status: "active", enabled: true, capabilities: { input: ["text"], output: ["text"], tools: true }, cost: [], limit: { context: 10000, output: 1000 }, time: { released: 0 }, variants: variants.map((id) => ({ id })), } } export function agent(id: string, selected?: AgentInfo["model"]): AgentInfo { return { id, name: id, model: selected, mode: "primary", hidden: false, permissions: [], request: { settings: {}, headers: {}, body: {} }, } } export function session(id: string, selected?: SessionInfo["model"], agent = "build"): SessionInfo { return { id, agent, model: selected, title: id, location: { directory }, projectID: "project", cost: 0, tokens: { input: 0, output: 0, reasoning: 0, cache: { read: 0, write: 0 } }, time: { created: 0, updated: 0 }, } }