diff --git a/packages/opencode/src/agent/agent.ts b/packages/opencode/src/agent/agent.ts index 355718b6bf..1ad3e9e4fa 100644 --- a/packages/opencode/src/agent/agent.ts +++ b/packages/opencode/src/agent/agent.ts @@ -94,6 +94,7 @@ export const layer = Layer.effect( question: "deny", plan_enter: "deny", plan_exit: "deny", + edit: "ask", // mirrors github.com/github/gitignore Node.gitignore pattern for .env files read: { "*": "allow", diff --git a/packages/opencode/src/cli/cmd/run.ts b/packages/opencode/src/cli/cmd/run.ts index 0874beee16..ed962ffa51 100644 --- a/packages/opencode/src/cli/cmd/run.ts +++ b/packages/opencode/src/cli/cmd/run.ts @@ -367,6 +367,11 @@ export const RunCommand = cmd({ action: "deny", pattern: "*", }, + { + permission: "edit", + action: "allow", + pattern: "*", + }, ] function title() { 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 1429e53195..e7f9956608 100644 --- a/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx +++ b/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx @@ -106,6 +106,7 @@ export function Prompt(props: PromptProps) { const renderer = useRenderer() 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 ?? []) @@ -228,6 +229,16 @@ export function Prompt(props: PromptProps) { command.register(() => { return [ + { + title: autoaccept() === "none" ? "Enable autoedit" : "Disable autoedit", + value: "permission.auto_accept.toggle", + search: "toggle permissions", + category: "Agent", + onSelect: (dialog) => { + setAutoaccept(() => (autoaccept() === "none" ? "edit" : "none")) + dialog.clear() + }, + }, { title: "Clear prompt", value: "prompt.clear", @@ -1221,11 +1232,14 @@ export function Prompt(props: PromptProps) { )} - - - {props.right} - - + + + + autoedit + + + {props.right} + 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 dda9a5a8ed..dd261b26f9 100644 --- a/packages/opencode/src/cli/cmd/tui/ui/dialog-select.tsx +++ b/packages/opencode/src/cli/cmd/tui/ui/dialog-select.tsx @@ -37,6 +37,7 @@ export interface DialogSelectOption { title: string value: T description?: string + search?: string footer?: JSX.Element | string category?: string categoryView?: JSX.Element @@ -93,8 +94,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) diff --git a/packages/opencode/test/agent/agent.test.ts b/packages/opencode/test/agent/agent.test.ts index 50a3668f98..c2ed6a1b01 100644 --- a/packages/opencode/test/agent/agent.test.ts +++ b/packages/opencode/test/agent/agent.test.ts @@ -224,8 +224,8 @@ test("agent permission config merges with defaults", async () => { expect(build).toBeDefined() // Specific pattern is denied expect(Permission.evaluate("bash", "rm -rf *", build!.permission).action).toBe("deny") - // Edit still allowed - expect(evalPerm(build, "edit")).toBe("allow") + // Edit still asks (default behavior) + expect(evalPerm(build, "edit")).toBe("ask") }, }) })