Buckets:
| import type { TuiDialogSelectOption, TuiPluginApi, TuiSlotProps } from "@opencode-ai/plugin/tui" | |
| import type { TuiConfig } from "../config" | |
| import type { useEvent } from "../context/event" | |
| import type { useRoute } from "../context/route" | |
| import type { useSDK } from "../context/sdk" | |
| import type { useSync } from "../context/sync" | |
| import type { useTheme } from "../context/theme" | |
| import { Dialog as DialogUI, type useDialog } from "../ui/dialog" | |
| import type { useOpencodeKeymap } from "../keymap" | |
| import type { useKV } from "../context/kv" | |
| import { DialogAlert } from "../ui/dialog-alert" | |
| import { DialogConfirm } from "../ui/dialog-confirm" | |
| import { DialogPrompt } from "../ui/dialog-prompt" | |
| import { DialogSelect, type DialogSelectOption as SelectOption } from "../ui/dialog-select" | |
| import { Prompt } from "../component/prompt" | |
| import type { useToast } from "../ui/toast" | |
| import * as Keymap from "../keymap" | |
| import { createCommandShim } from "./command-shim" | |
| import type { PluginRoutes } from "./api" | |
| export type { RouteMap } from "./api" | |
| export { createPluginRoutes, createTuiApi } from "./api" | |
| type Input = { | |
| version: string | |
| tuiConfig: TuiConfig.Resolved | |
| dialog: ReturnType<typeof useDialog> | |
| keymap: ReturnType<typeof useOpencodeKeymap> | |
| kv: ReturnType<typeof useKV> | |
| route: ReturnType<typeof useRoute> | |
| routes: PluginRoutes | |
| event: ReturnType<typeof useEvent> | |
| sdk: ReturnType<typeof useSDK> | |
| sync: ReturnType<typeof useSync> | |
| theme: ReturnType<typeof useTheme> | |
| toast: ReturnType<typeof useToast> | |
| renderer: TuiPluginApi["renderer"] | |
| attention: TuiPluginApi["attention"] | |
| Slot: TuiPluginApi["ui"]["Slot"] | |
| } | |
| function routeNavigate(route: ReturnType<typeof useRoute>, name: string, params?: Record<string, unknown>) { | |
| if (name === "home") { | |
| route.navigate({ type: "home" }) | |
| return | |
| } | |
| if (name === "session") { | |
| const sessionID = params?.sessionID | |
| if (typeof sessionID !== "string") return | |
| route.navigate({ type: "session", sessionID }) | |
| return | |
| } | |
| route.navigate({ type: "plugin", id: name, data: params }) | |
| } | |
| function routeCurrent(route: ReturnType<typeof useRoute>): TuiPluginApi["route"]["current"] { | |
| if (route.data.type === "home") return { name: "home" } | |
| if (route.data.type === "session") { | |
| return { | |
| name: "session", | |
| params: { | |
| sessionID: route.data.sessionID, | |
| prompt: route.data.prompt, | |
| }, | |
| } | |
| } | |
| return { | |
| name: route.data.id, | |
| params: route.data.data, | |
| } | |
| } | |
| function mapOption<Value>(item: TuiDialogSelectOption<Value>): SelectOption<Value> { | |
| return { | |
| ...item, | |
| onSelect: () => item.onSelect?.(), | |
| } | |
| } | |
| function pickOption<Value>(item: SelectOption<Value>): TuiDialogSelectOption<Value> { | |
| return { | |
| title: item.title, | |
| value: item.value, | |
| description: item.description, | |
| footer: item.footer, | |
| category: item.category, | |
| disabled: item.disabled, | |
| } | |
| } | |
| function mapOptionCb<Value>(cb?: (item: TuiDialogSelectOption<Value>) => void) { | |
| if (!cb) return | |
| return (item: SelectOption<Value>) => cb(pickOption(item)) | |
| } | |
| function stateApi(sync: ReturnType<typeof useSync>): TuiPluginApi["state"] { | |
| return { | |
| get ready() { | |
| return sync.ready | |
| }, | |
| get config() { | |
| return sync.data.config | |
| }, | |
| get provider() { | |
| return sync.data.provider | |
| }, | |
| get path() { | |
| return sync.path | |
| }, | |
| get vcs() { | |
| if (!sync.data.vcs) return | |
| return { | |
| branch: sync.data.vcs.branch, | |
| } | |
| }, | |
| session: { | |
| count() { | |
| return sync.data.session.length | |
| }, | |
| get(sessionID) { | |
| return sync.session.get(sessionID) | |
| }, | |
| diff(sessionID) { | |
| return (sync.data.session_diff[sessionID] ?? []).flatMap((item) => | |
| item.file === undefined ? [] : [{ ...item, file: item.file }], | |
| ) | |
| }, | |
| todo(sessionID) { | |
| return sync.data.todo[sessionID] ?? [] | |
| }, | |
| messages(sessionID) { | |
| return sync.data.message[sessionID] ?? [] | |
| }, | |
| status(sessionID) { | |
| return sync.data.session_status[sessionID] | |
| }, | |
| permission(sessionID) { | |
| return sync.data.permission[sessionID] ?? [] | |
| }, | |
| question(sessionID) { | |
| return sync.data.question[sessionID] ?? [] | |
| }, | |
| }, | |
| part(messageID) { | |
| return sync.data.part[messageID] ?? [] | |
| }, | |
| lsp() { | |
| return sync.data.lsp.map((item) => ({ id: item.id, root: item.root, status: item.status })) | |
| }, | |
| mcp() { | |
| return Object.entries(sync.data.mcp) | |
| .sort(([a], [b]) => a.localeCompare(b)) | |
| .map(([name, item]) => ({ | |
| name, | |
| status: item.status, | |
| error: item.status === "failed" ? item.error : undefined, | |
| })) | |
| }, | |
| } | |
| } | |
| function appApi(version: string): TuiPluginApi["app"] { | |
| return { | |
| get version() { | |
| return version | |
| }, | |
| } | |
| } | |
| export function createTuiApiAdapters(input: Input): Omit<TuiPluginApi, "lifecycle"> { | |
| return { | |
| app: appApi(input.version), | |
| attention: input.attention, | |
| // Keep deprecated `api.command` working for v1 plugins; remove in v2. | |
| command: createCommandShim(input.keymap, input.dialog, input.tuiConfig.keybinds), | |
| keys: { | |
| formatSequence(parts) { | |
| return Keymap.formatKeySequence(parts, input.tuiConfig) | |
| }, | |
| formatBindings(bindings) { | |
| return Keymap.formatKeyBindings(bindings, input.tuiConfig) | |
| }, | |
| }, | |
| keymap: input.keymap, | |
| mode: { | |
| current() { | |
| return Keymap.getOpencodeModeStack(input.keymap).current() | |
| }, | |
| push(mode) { | |
| return Keymap.getOpencodeModeStack(input.keymap).push(mode) | |
| }, | |
| }, | |
| route: { | |
| register(list) { | |
| return input.routes.register(list) | |
| }, | |
| navigate(name, params) { | |
| routeNavigate(input.route, name, params) | |
| }, | |
| get current() { | |
| return routeCurrent(input.route) | |
| }, | |
| }, | |
| ui: { | |
| Dialog(props) { | |
| return ( | |
| <DialogUI size={props.size} onClose={props.onClose}> | |
| {props.children} | |
| </DialogUI> | |
| ) | |
| }, | |
| DialogAlert(props) { | |
| return <DialogAlert {...props} /> | |
| }, | |
| DialogConfirm(props) { | |
| return <DialogConfirm {...props} /> | |
| }, | |
| DialogPrompt(props) { | |
| return <DialogPrompt {...props} description={props.description} /> | |
| }, | |
| DialogSelect(props) { | |
| return ( | |
| <DialogSelect | |
| title={props.title} | |
| placeholder={props.placeholder} | |
| options={props.options.map(mapOption)} | |
| flat={props.flat} | |
| onMove={mapOptionCb(props.onMove)} | |
| onFilter={props.onFilter} | |
| onSelect={mapOptionCb(props.onSelect)} | |
| skipFilter={props.skipFilter} | |
| current={props.current} | |
| /> | |
| ) | |
| }, | |
| Slot<Name extends string>(props: TuiSlotProps<Name>) { | |
| return <input.Slot {...props} /> | |
| }, | |
| Prompt(props) { | |
| return ( | |
| <Prompt | |
| sessionID={props.sessionID} | |
| visible={props.visible} | |
| disabled={props.disabled} | |
| onSubmit={props.onSubmit} | |
| ref={props.ref} | |
| hint={props.hint} | |
| right={props.right} | |
| showPlaceholder={props.showPlaceholder} | |
| placeholders={props.placeholders} | |
| /> | |
| ) | |
| }, | |
| toast(inputToast) { | |
| input.toast.show({ | |
| title: inputToast.title, | |
| message: inputToast.message, | |
| variant: inputToast.variant ?? "info", | |
| duration: inputToast.duration, | |
| }) | |
| }, | |
| dialog: { | |
| replace(render, onClose) { | |
| input.dialog.replace(render, onClose) | |
| }, | |
| clear() { | |
| input.dialog.clear() | |
| }, | |
| setSize(size) { | |
| input.dialog.setSize(size) | |
| }, | |
| get size() { | |
| return input.dialog.size | |
| }, | |
| get depth() { | |
| return input.dialog.stack.length | |
| }, | |
| get open() { | |
| return input.dialog.stack.length > 0 | |
| }, | |
| }, | |
| }, | |
| get tuiConfig() { | |
| return input.tuiConfig | |
| }, | |
| kv: { | |
| get(key, fallback) { | |
| return input.kv.get(key, fallback) | |
| }, | |
| set(key, value) { | |
| input.kv.set(key, value) | |
| }, | |
| get ready() { | |
| return input.kv.ready | |
| }, | |
| }, | |
| state: stateApi(input.sync), | |
| get client() { | |
| return input.sdk.client | |
| }, | |
| event: input.event, | |
| renderer: input.renderer, | |
| slots: { | |
| register() { | |
| throw new Error("slots.register is only available in plugin context") | |
| }, | |
| }, | |
| plugins: { | |
| list() { | |
| return [] | |
| }, | |
| async activate() { | |
| return false | |
| }, | |
| async deactivate() { | |
| return false | |
| }, | |
| async add() { | |
| return false | |
| }, | |
| async install() { | |
| return { | |
| ok: false, | |
| message: "plugins.install is only available in plugin context", | |
| } | |
| }, | |
| }, | |
| theme: { | |
| get current() { | |
| return input.theme.theme | |
| }, | |
| get selected() { | |
| return input.theme.selected | |
| }, | |
| has(name) { | |
| return input.theme.has(name) | |
| }, | |
| set(name) { | |
| return input.theme.set(name) | |
| }, | |
| async install(_jsonPath) { | |
| throw new Error("theme.install is only available in plugin context") | |
| }, | |
| mode() { | |
| return input.theme.mode() | |
| }, | |
| get ready() { | |
| return input.theme.ready | |
| }, | |
| }, | |
| } | |
| } | |
Xet Storage Details
- Size:
- 9.54 kB
- Xet hash:
- f7d5b42cb0227b445a7eabb9e6c4cb4922be8177cd99fd68828e2470d4630812
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.