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 bd2b0e352b..57e0c101a8 100644 --- a/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx +++ b/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx @@ -157,6 +157,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 ?? []) @@ -199,7 +200,7 @@ export function Prompt(props: PromptProps) { const [warpNotice, setWarpNotice] = createSignal() const [cursorVersion, setCursorVersion] = createSignal(0) const currentProviderLabel = createMemo(() => local.model.parsed().provider) - const hasRightContent = createMemo(() => Boolean(props.right)) + const hasRightContent = createMemo(() => Boolean(props.right) || autoaccept() === "edit") function selectWorkspace(selection: WorkspaceSelection | undefined) { setWorkspaceSelection(selection) @@ -404,6 +405,15 @@ export function Prompt(props: PromptProps) { const promptCommands = createMemo(() => [ + { + title: autoaccept() === "none" ? "Enable autoedit" : "Disable autoedit", + name: "permission.auto_accept.toggle", + category: "Agent", + run: () => { + setAutoaccept(() => (autoaccept() === "none" ? "edit" : "none")) + dialog.clear() + }, + }, { title: "Clear prompt", name: "prompt.clear", @@ -1588,6 +1598,11 @@ export function Prompt(props: PromptProps) { {props.right} + + + autoedit + + diff --git a/packages/opencode/src/cli/cmd/tui/config/keybind.ts b/packages/opencode/src/cli/cmd/tui/config/keybind.ts index c03123aed1..ba6506ea64 100644 --- a/packages/opencode/src/cli/cmd/tui/config/keybind.ts +++ b/packages/opencode/src/cli/cmd/tui/config/keybind.ts @@ -146,6 +146,7 @@ export const Definitions = { display_thinking: keybind("none", "Toggle thinking blocks visibility"), prompt_submit: keybind("none", "Submit prompt"), + permission_auto_accept_toggle: keybind("none", "Toggle auto-accept for edit permissions"), prompt_editor_context_clear: keybind("none", "Clear editor context"), prompt_skills: keybind("none", "Open skill selector"), prompt_stash: keybind("none", "Stash prompt"), @@ -340,6 +341,7 @@ export const CommandMap = { tool_details: "session.toggle.actions", display_thinking: "session.toggle.thinking", prompt_submit: "prompt.submit", + permission_auto_accept_toggle: "permission.auto_accept.toggle", prompt_editor_context_clear: "prompt.editor_context.clear", prompt_skills: "prompt.skills", prompt_stash: "prompt.stash", 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)