diff --git a/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx b/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx
index de2a75dc46..2c80910546 100644
--- a/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx
+++ b/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx
@@ -160,6 +160,7 @@ export function Prompt(props: PromptProps) {
const dimensions = useTerminalDimensions()
const { theme, syntax } = useTheme()
const kv = useKV()
+ const [autoaccept, setAutoaccept] = kv.signal<"none" | "edit">("permission_auto_accept", "edit")
const animationsEnabled = createMemo(() => kv.get("animations_enabled", true))
const list = createMemo(() => props.placeholders?.normal ?? [])
const shell = createMemo(() => props.placeholders?.shell ?? [])
@@ -408,6 +409,17 @@ export function Prompt(props: PromptProps) {
const promptCommands = createMemo(() =>
[
+ {
+ title: autoaccept() === "none" ? "Enable autoedit" : "Disable autoedit",
+ name: "permission.auto_accept.toggle",
+ search: "toggle permissions",
+ keybind: "permission_auto_accept_toggle",
+ category: "Agent",
+ run: () => {
+ setAutoaccept(() => (autoaccept() === "none" ? "edit" : "none"))
+ dialog.clear()
+ },
+ },
{
title: "Clear prompt",
name: "prompt.clear",
@@ -631,6 +643,7 @@ export function Prompt(props: PromptProps) {
useBindings(() => ({
enabled: command.matcher,
bindings: tuiConfig.keybinds.gather("prompt.palette", [
+ "permission.auto_accept.toggle",
"prompt.submit",
"prompt.editor",
"prompt.editor_context.clear",
@@ -1595,6 +1608,11 @@ export function Prompt(props: PromptProps) {
+
+
+ autoedit
+
+
{props.right}
diff --git a/packages/opencode/src/cli/cmd/tui/config/keybind.ts b/packages/opencode/src/cli/cmd/tui/config/keybind.ts
index a375573828..f08d920ac0 100644
--- a/packages/opencode/src/cli/cmd/tui/config/keybind.ts
+++ b/packages/opencode/src/cli/cmd/tui/config/keybind.ts
@@ -110,7 +110,8 @@ export const Definitions = {
console_org_switch: keybind("none", "Switch console organization"),
agent_list: keybind("a", "List agents"),
agent_cycle: keybind("tab", "Next agent"),
- agent_cycle_reverse: keybind("shift+tab", "Previous agent"),
+ agent_cycle_reverse: keybind("none", "Previous agent"),
+ permission_auto_accept_toggle: keybind("shift+tab", "Toggle auto-accept mode for permissions"),
variant_cycle: keybind("ctrl+t", "Cycle model variants"),
variant_list: keybind("none", "List model variants"),
@@ -294,6 +295,7 @@ export const CommandMap = {
agent_list: "agent.list",
agent_cycle: "agent.cycle",
agent_cycle_reverse: "agent.cycle.reverse",
+ permission_auto_accept_toggle: "permission.auto_accept.toggle",
variant_cycle: "variant.cycle",
variant_list: "variant.list",
messages_page_up: "session.page.up",
diff --git a/packages/opencode/src/cli/cmd/tui/context/sync.tsx b/packages/opencode/src/cli/cmd/tui/context/sync.tsx
index 9f8a384f77..40d74f5613 100644
--- a/packages/opencode/src/cli/cmd/tui/context/sync.tsx
+++ b/packages/opencode/src/cli/cmd/tui/context/sync.tsx
@@ -111,6 +111,7 @@ export const { use: useSync, provider: SyncProvider } = createSimpleContext({
const project = useProject()
const sdk = useSDK()
const kv = useKV()
+ const [autoaccept] = kv.signal<"none" | "edit">("permission_auto_accept", "edit")
const fullSyncedSessions = new Set()
@@ -152,6 +153,13 @@ export const { use: useSync, provider: SyncProvider } = createSimpleContext({
case "permission.asked": {
const request = event.properties
+ if (autoaccept() === "edit" && request.permission === "edit") {
+ void sdk.client.permission.reply({
+ reply: "once",
+ requestID: request.id,
+ })
+ break
+ }
const requests = store.permission[request.sessionID]
if (!requests) {
setStore("permission", request.sessionID, [request])
diff --git a/packages/opencode/src/cli/cmd/tui/ui/dialog-select.tsx b/packages/opencode/src/cli/cmd/tui/ui/dialog-select.tsx
index 700735d38c..e318309c6b 100644
--- a/packages/opencode/src/cli/cmd/tui/ui/dialog-select.tsx
+++ b/packages/opencode/src/cli/cmd/tui/ui/dialog-select.tsx
@@ -51,6 +51,7 @@ export interface DialogSelectOption {
title: string
value: T
description?: string
+ search?: string
footer?: JSX.Element | string
category?: string
categoryView?: JSX.Element
@@ -126,8 +127,8 @@ export function DialogSelect(props: DialogSelectProps) {
// users typically search by the item name, and not its category.
const result = fuzzysort
.go(needle, options, {
- keys: ["title", "category"],
- scoreFn: (r) => r[0].score * 2 + r[1].score,
+ keys: ["title", "category", "search"],
+ scoreFn: (r) => r[0].score * 2 + r[1].score + r[2].score,
})
.map((x) => x.obj)