cleanup sdk

actual-tui-plugins
Sebastian Herrlinger 2026-03-04 23:30:05 +01:00
parent 8743dddde6
commit 3cc33e39e7
4 changed files with 29 additions and 29 deletions

View File

@ -150,7 +150,6 @@ export function tui(input: {
}
const renderer = await createCliRenderer(rendererConfig(input.config))
TuiPlugin.initializeSlots(renderer)
await render(() => {
return (
@ -165,7 +164,6 @@ export function tui(input: {
<TuiConfigProvider config={input.config}>
<SDKProvider
url={input.url}
renderer={renderer}
directory={input.directory}
fetch={input.fetch}
headers={input.headers}
@ -215,6 +213,13 @@ function App() {
const kv = useKV()
const command = useCommandDialog()
const sdk = useSDK()
TuiPlugin.init({
client: sdk.client,
event: sdk.event,
renderer,
}).catch((error) => {
console.error("Failed to load TUI plugins", error)
})
const toast = useToast()
const { theme, mode, setMode } = useTheme()
const sync = useSync()

View File

@ -1,9 +1,7 @@
import { createOpencodeClient, type Event } from "@opencode-ai/sdk/v2"
import type { CliRenderer } from "@opentui/core"
import { createSimpleContext } from "./helper"
import { createGlobalEmitter } from "@solid-primitives/event-bus"
import { batch, onCleanup, onMount } from "solid-js"
import { TuiPlugin } from "../plugin"
export type EventSource = {
on: (handler: (event: Event) => void) => () => void
@ -14,7 +12,6 @@ export const { use: useSDK, provider: SDKProvider } = createSimpleContext({
name: "SDK",
init: (props: {
url: string
renderer: CliRenderer
directory?: string
fetch?: typeof fetch
headers?: RequestInit["headers"]
@ -41,14 +38,6 @@ export const { use: useSDK, provider: SDKProvider } = createSimpleContext({
[key in Event["type"]]: Extract<Event, { type: key }>
}>()
TuiPlugin.init({
client: sdk,
event: emitter,
renderer: props.renderer,
}).catch((error) => {
console.error("Failed to load TUI plugins", error)
})
let queue: Event[] = []
let timer: Timer | undefined
let last = 0

View File

@ -54,19 +54,24 @@ function getTuiPlugin<Renderer>(value: unknown) {
return value.tui
}
function isCliRenderer(value: unknown): value is CliRenderer {
if (!isRecord(value)) return false
if (!("once" in value)) return false
return typeof value.once === "function"
}
export namespace TuiPlugin {
const log = Log.create({ service: "tui.plugin" })
let loaded: Promise<void> | undefined
let view: Slot = empty
let api: TuiSlots = {
register() {
return () => {}
},
}
export const Slot: Slot = (props) => view(props)
export function initializeSlots(renderer: CliRenderer) {
function setupSlots(renderer: unknown): TuiSlots {
if (!isCliRenderer(renderer)) {
throw new TypeError("Invalid TUI renderer")
}
const reg = createSolidSlotRegistry<TuiSlotMap, TuiSlotContext>(
renderer,
{},
@ -85,7 +90,7 @@ export namespace TuiPlugin {
const slot = createSlot<TuiSlotMap, TuiSlotContext>(reg)
view = (props) => slot(props)
api = {
return {
register(pluginSlot) {
if (!isTuiSlotPlugin(pluginSlot)) return () => {}
return reg.register(pluginSlot)
@ -95,16 +100,15 @@ export namespace TuiPlugin {
export async function init<Renderer>(input: InitInput<Renderer>) {
if (loaded) return loaded
loaded = load(input)
loaded = load({
...input,
slots: setupSlots(input.renderer),
})
return loaded
}
async function load<Renderer>(input: InitInput<Renderer>) {
async function load<Renderer>(input: TuiPluginInput<Renderer>) {
const dir = process.cwd()
const ctx: TuiPluginInput<Renderer> = {
...input,
slots: api,
}
await Instance.provide({
directory: dir,
@ -142,11 +146,11 @@ export namespace TuiPlugin {
if (theme) registerThemes(theme)
const slotPlugin = getTuiSlotPlugin(entry)
if (slotPlugin) ctx.slots.register(slotPlugin)
if (slotPlugin) input.slots.register(slotPlugin)
const tuiPlugin = getTuiPlugin<Renderer>(entry)
if (!tuiPlugin) continue
await tuiPlugin(ctx, Config.pluginOptions(item))
await tuiPlugin(input, Config.pluginOptions(item))
}
}
},

View File

@ -88,7 +88,9 @@ test("ignores function-only tui exports and loads object exports", async () => {
event: {
on: () => () => {},
},
renderer: {},
renderer: {
once: () => undefined,
},
})
expect(await fs.readFile(tmp.extra.objMarker, "utf8")).toBe("called")