tui: remove legacy V1 CLI TUI integration to simplify startup

This commit is contained in:
Dax Raad 2026-07-13 01:05:14 -04:00
commit a43de3f86d
13 changed files with 8 additions and 542 deletions

View file

@ -77,7 +77,6 @@ import { ArgsProvider, useArgs, type Args } from "./context/args"
import open from "open"
import { PromptRefProvider, usePromptRef } from "./context/prompt"
import { Config, ConfigProvider, useConfig } from "./config"
import { TuiConfigV1 } from "./config/v1"
import { createTuiApiAdapters } from "./plugin/adapters"
import { createTuiApi } from "./plugin/api"
import { createPluginRuntime, PluginRuntimeProvider, usePluginRuntime, type TuiPluginHost } from "./plugin/runtime"
@ -139,7 +138,6 @@ const appBindingCommands = [
"diff.open",
"app.debug",
"app.console",
"app.heap_snapshot",
"terminal.suspend",
"terminal.title.toggle",
"app.toggle.animations",
@ -155,8 +153,7 @@ export type TuiInput = {
reload?: () => Promise<void>
}
args: Args
config: Config.Interface | TuiConfigV1.Resolved
onSnapshot?: () => Promise<string[]>
config: Config.Interface
pluginHost: TuiPluginHost
terminalHandoff?: () => Promise<
| {
@ -201,45 +198,12 @@ function isVersionGreater(left: string, right: string) {
return a.prerelease.localeCompare(b.prerelease, undefined, { numeric: true }) > 0
}
function fromV1(config: TuiConfigV1.Resolved): Config.Info {
return {
theme: config.theme ? { name: config.theme } : undefined,
plugins: config.plugin?.map((plugin) =>
typeof plugin === "string" ? plugin : { package: plugin[0], options: plugin[1] },
),
leader: { timeout: config.leader_timeout },
scroll:
config.scroll_speed === undefined && config.scroll_acceleration === undefined
? undefined
: { speed: config.scroll_speed, acceleration: config.scroll_acceleration?.enabled },
attention: config.attention,
diffs: config.diff_style === undefined ? undefined : { view: config.diff_style === "stacked" ? "unified" : "auto" },
mouse: config.mouse,
}
}
function isConfigInterface(config: Config.Interface | TuiConfigV1.Resolved): config is Config.Interface {
return (
"get" in config && typeof config.get === "function" && "update" in config && typeof config.update === "function"
)
}
export const run = Effect.fn("Tui.run")(function* (input: TuiInput) {
const log = input.log ?? (() => {})
const global = yield* Global.Service
const configInput = input.config
const loaded = yield* Effect.gen(function* () {
if (isConfigInterface(configInput)) {
return {
service: configInput,
info: yield* Effect.tryPromise(() => configInput.get()),
legacy: undefined,
}
}
return { service: undefined, info: fromV1(configInput), legacy: configInput }
const config = Config.resolve(yield* Effect.tryPromise(() => input.config.get()), {
terminalSuspend: process.platform !== "win32",
})
const config = Config.resolve(loaded.info, { terminalSuspend: process.platform !== "win32" })
if (loaded.legacy) config.keybinds = loaded.legacy.keybinds
const options = { baseUrl: input.server.endpoint.url, headers: Service.headers(input.server.endpoint) }
const api = OpenCode.make(options)
const directory = yield* Effect.tryPromise(() => api.file.list({ location: { directory: process.cwd() } })).pipe(
@ -376,7 +340,7 @@ export const run = Effect.fn("Tui.run")(function* (input: TuiInput) {
<ArgsProvider {...input.args}>
<ConfigProvider
config={config}
service={loaded.service}
service={input.config}
options={{ terminalSuspend: process.platform !== "win32" }}
>
<KVProvider>
@ -412,9 +376,7 @@ export const run = Effect.fn("Tui.run")(function* (input: TuiInput) {
<EditorContextProvider>
<LocationProvider>
<App
onSnapshot={input.onSnapshot}
pluginHost={input.pluginHost}
pluginConfig={loaded.legacy ?? config}
pair={
input.server.endpoint.auth
? input.server.endpoint.auth
@ -473,15 +435,12 @@ export const run = Effect.fn("Tui.run")(function* (input: TuiInput) {
})
function App(props: {
onSnapshot?: () => Promise<string[]>
pluginHost: TuiPluginHost
pluginConfig: any
pair?: DialogPairCredentials
}) {
const log = useLog({ component: "app" })
const startup = useTuiStartup()
const configContext = useConfig()
const config = configContext.data
const config = useConfig().data
const route = useRoute()
const dimensions = useTerminalDimensions()
const renderer = useRenderer()
@ -555,7 +514,6 @@ function App(props: {
props.pluginHost
.start({
api,
config: props.pluginConfig,
runtime: pluginRuntime,
dispose: () => attention.dispose(),
})
@ -859,7 +817,6 @@ function App(props: {
name: "opencode.settings",
title: "Open settings",
slashName: "settings",
enabled: configContext.writable,
run: () => {
dialog.replace(() => <DialogConfig />)
},
@ -983,20 +940,6 @@ function App(props: {
dialog.clear()
},
},
{
name: "app.heap_snapshot",
title: "Write heap snapshot",
category: "System",
run: async () => {
const files = await props.onSnapshot?.()
toast.show({
variant: "info",
message: `Heap snapshot written to ${files?.join(", ")}`,
duration: 5000,
})
dialog.clear()
},
},
{
name: "terminal.suspend",
title: "Suspend terminal",

View file

@ -179,7 +179,6 @@ export function resolve(input: Info, options: { terminalSuspend: boolean }): Res
const ConfigContext = createContext<{
data: Resolved
update: Interface["update"]
writable: boolean
}>()
export function ConfigProvider(props: {
@ -197,7 +196,7 @@ export function ConfigProvider(props: {
return info
}
return (
<ConfigContext.Provider value={{ data: config, update, writable: !!host }}>{props.children}</ConfigContext.Provider>
<ConfigContext.Provider value={{ data: config, update }}>{props.children}</ConfigContext.Provider>
)
}

View file

@ -60,7 +60,6 @@ export type PluginRuntime = ReturnType<typeof createPluginRuntime>
export type TuiPluginHost = {
start(input: {
api: TuiPluginApi
config: any
runtime: PluginRuntime
dispose?: () => void
}): Promise<void>