opencode-plugin-question-force-closeopencode TUI plugin that forces a clickable close button while the question tool is waiting for input.
0
309
近 7 天 17
34.9
生态多维模型
14 天前
2026-08-05
快速安装与配置
opencode.json写入当前项目的 opencode.json,只对这个仓库生效。
opencode.json
{
"$schema": "https://opencode.ai/config.json",
"plugin": ["opencode-plugin-question-force-close@1.0.1"]
}写入 ~/.config/opencode/opencode.json,对所有项目生效。
~/.config/opencode/opencode.json
{
"$schema": "https://opencode.ai/config.json",
"plugin": ["opencode-plugin-question-force-close@1.0.1"]
}若你要在本地改造这个插件,先装到项目里再从本地路径引用。
shell
pnpm add -D opencode-plugin-question-force-closeopencode 启动时会通过内嵌运行时自动加载 npm 依赖并缓存至本地目录,无需手动在全局环境执行安装。
English | 简体中文
An opencode TUI plugin that forces a clickable close button while the question tool is waiting for input.
opencode's built-in question dialog has no close affordance of its own — it can normally only be dismissed by pressing esc. When the dialog is off-screen (scrolled away) or you're on a setup where hitting esc is awkward, there is no visible way to abort the question. This plugin renders a prominent ✕ Force close question button that calls question.reject on click, aborting the tool — equivalent to pressing esc, but always visible and clickable.

Install
From npm (recommended)
Add the plugin to your opencode TUI config:
// .opencode/tui.json
{
"$schema": "https://opencode.ai/tui.json",
"plugin": ["opencode-plugin-question-force-close"]
}
opencode installs npm plugins automatically via Bun on startup.
From a local file
// .opencode/tui.json
{
"$schema": "https://opencode.ai/tui.json",
"plugin": ["../path/to/plugin.tsx"]
}
Then install the plugin's runtime dependencies at the project root:
bun install # or: bun add solid-js@1.9.12 @opentui/solid@0.4.5
Usage
Start the interactive TUI:
opencodeopencode run "..."runs headless and does not load TUI plugins. You must use the interactive TUI.Trigger any agent call that invokes the
questiontool.A red
✕ Force close questionbutton appears at the bottom-right, directly beneath the question dialog. Click it (mouse) to dismiss the question and abort the tool. The button auto-hides once the question is answered or dismissed.
How it works
The plugin subscribes to the question lifecycle via the TUI event bus:
| Event | Action |
|---|---|
question.asked |
record the pending request id, show button |
question.replied |
clear pending, hide button |
question.rejected |
clear pending, hide button |
On click, it calls api.client.question.reject({ requestID, directory }), the same SDK call the built-in esc keybinding uses.
The button is rendered through opencode's host-slot system (api.slots.register) using SolidJS, the same reactivity framework the opencode TUI is built on.
Limitations
- Position is bottom-right, not top-right. opencode's TUI uses a relative box layout with no native floating-overlay slot. The question dialog itself (and its
esc dismisshint) is hard-coded inside opencode's source and cannot be injected into by plugins. Theapp_bottomhost slot — wrapped in aflexShrink: 0box directly beneath the session area — is the closest slot that is guaranteed visible while a question is pending. A true top-right floating button would require patching opencode itself. - Requires the interactive TUI. Headless mode (
opencode run) does not load TUI plugins. - Uses an undocumented API. opencode's official plugin docs only cover server plugins (hooks). TUI rendering plugins (
{ id, tui }modules,api.slots, the TUI event bus) are internal/undocumented as of opencode 1.18.x. This plugin may need updates if those internals change.
Requirements
| Package | Version | Notes |
|---|---|---|
| opencode | ≥ 1.18.0 | TUI plugin + host-slot system |
@opentui/solid |
0.4.5 | pinned exact; interlocked with the opencode 1.18.x host |
solid-js |
1.9.12 | pinned exact; peerDependency of @opentui/solid@0.4.5 |
@opencode-ai/plugin |
1.18.13 | optional peer (types only at runtime) |
opencode bundles its own copies of
solid-jsand@opentui/solidand redirects plugin imports to the host instance at runtime, so there is no "double SolidJS instance" problem even though the plugin ships its own copies.
Project layout
opencode-plugin-question-force-close/
├── plugin.tsx # the plugin (default exports { id, tui })
├── package.json # npm metadata + pinned deps
├── README.md
├── LICENSE
└── .opencode/ # local dev / test harness (NOT published)
├── opencode.json
└── tui.json # loads the plugin via "../plugin.tsx"
Develop
git clone https://github.com/zylcold/opencode-plugin-question-force-close.git
cd opencode-plugin-question-force-close
bun install # install solid-js + @opentui/solid at root
opencode # interactive TUI; trigger a question to test
The .opencode/tui.json in this repo already points at ../plugin.tsx, so cloning + bun install + opencode is enough to run the plugin locally.
Debugging tips
TUI plugin failures are silent by default — the interactive renderer swallows console.*. If nothing renders, inject a disk probe inside plugin.tsx:
import { appendFileSync } from "node:fs"
const diag = (stage: string, data?: unknown) =>
appendFileSync("/tmp/qfc.log", `${stage} ${JSON.stringify(data ?? "")}\n`)
diag("module-imported") // trace each lifecycle stage