// opencode v2 TUI plugin: one key toggles the "verbose view". // // v2 dropped the v1 tool-details / timestamps / generic-output toggles. The session view now has two // display toggles that matter: thinking blocks (session.thinking show|hide) and exploration grouping // (session.grouping auto|none — "auto" folds read/glob/grep tool calls into one collapsed group). // Verbose = thinking expanded AND tool calls shown individually. Both settings persist in the TUI config. // // State is read from the built-in commands' live titles (the only plugin-visible signal): // session.toggle.thinking → "Collapse thinking" while expanded, else "Expand thinking" // session.toggle.exploration_grouping → "Show tool calls individually" while grouped, else "Group related tool calls" // then only the toggles that differ from the target are dispatched, so a mixed state converges. // // Auto-discovered from ~/.config/opencode/plugins/verbose/ (server.ts + this file). Key configurable // via plugin options; default v. Also /verbose and a command-palette entry. const THINKING = "session.toggle.thinking" const GROUPING = "session.toggle.exploration_grouping" type Command = { readonly id?: string; readonly title?: string } type Context = { readonly options?: Readonly> readonly keymap: { layer(input: () => { readonly commands?: readonly unknown[] }): void dispatch(id: string, input?: string): void commands(): readonly Command[] } readonly ui: { readonly toast: { show(o: { message: string; variant?: string; duration?: number }): void } } } export default { id: "coja.verbose", setup(context: Context) { const key = typeof context.options?.key === "string" && context.options.key ? (context.options.key as string) : "v" const title = (id: string) => context.keymap.commands().find((c) => c.id === id)?.title ?? "" context.keymap.layer(() => ({ commands: [ { id: "verbose.toggle", title: "Toggle verbose view (expand thinking, ungroup tool calls)", group: "Session", bind: key, palette: true, slash: { name: "verbose" }, run() { const thinkingTitle = title(THINKING) const groupingTitle = title(GROUPING) if (!thinkingTitle && !groupingTitle) { context.ui.toast.show({ message: "Verbose view: open a session first", variant: "warning", duration: 2000 }) return } const thinkingVerbose = thinkingTitle.startsWith("Collapse") const groupingVerbose = groupingTitle.startsWith("Group") const on = !(thinkingVerbose && groupingVerbose) if (thinkingTitle && thinkingVerbose !== on) context.keymap.dispatch(THINKING) if (groupingTitle && groupingVerbose !== on) context.keymap.dispatch(GROUPING) context.ui.toast.show({ message: on ? "Verbose view on" : "Verbose view off", variant: "info", duration: 1500 }) }, }, ], })) }, }