summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorAdam <[email protected]>2026-03-02 13:10:37 -0600
committerAdam <[email protected]>2026-03-02 13:10:37 -0600
commit78069369e2253c9788c09b7a71478d140c9741f2 (patch)
treee15011250cd1a92953dfe0584facbc26bcb92309
parent1cd77b10724ad87acc96790bec4a524614b20ad6 (diff)
downloadopencode-78069369e2253c9788c09b7a71478d140c9741f2.tar.gz
opencode-78069369e2253c9788c09b7a71478d140c9741f2.zip
fix(app): default auto-respond to false
-rw-r--r--packages/app/e2e/session/session-composer-dock.spec.ts11
-rw-r--r--packages/app/src/components/prompt-input.tsx29
-rw-r--r--packages/app/src/components/prompt-input/submit.test.ts38
-rw-r--r--packages/app/src/components/prompt-input/submit.ts5
-rw-r--r--packages/app/src/context/permission-auto-respond.test.ts4
-rw-r--r--packages/app/src/context/permission-auto-respond.ts2
6 files changed, 77 insertions, 12 deletions
diff --git a/packages/app/e2e/session/session-composer-dock.spec.ts b/packages/app/e2e/session/session-composer-dock.spec.ts
index deb87a062..4cf075fc9 100644
--- a/packages/app/e2e/session/session-composer-dock.spec.ts
+++ b/packages/app/e2e/session/session-composer-dock.spec.ts
@@ -142,6 +142,17 @@ test("default dock shows prompt input", async ({ page, sdk, gotoSession }) => {
})
})
+test("auto-accept toggle works before first submit", async ({ page, gotoSession }) => {
+ await gotoSession()
+
+ const button = page.locator('[data-action="prompt-permissions"]').first()
+ await expect(button).toBeVisible()
+ await expect(button).toHaveAttribute("aria-pressed", "false")
+
+ await setAutoAccept(page, true)
+ await setAutoAccept(page, false)
+})
+
test("blocked question flow unblocks after submit", async ({ page, sdk, gotoSession }) => {
await withDockSession(sdk, "e2e composer dock question", async (session) => {
await withDockSeed(sdk, session.id, async () => {
diff --git a/packages/app/src/components/prompt-input.tsx b/packages/app/src/components/prompt-input.tsx
index b99ac9373..ba5a33a47 100644
--- a/packages/app/src/components/prompt-input.tsx
+++ b/packages/app/src/components/prompt-input.tsx
@@ -243,6 +243,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
draggingType: "image" | "@mention" | null
mode: "normal" | "shell"
applyingHistory: boolean
+ pendingAutoAccept: boolean
}>({
popover: null,
historyIndex: -1,
@@ -251,6 +252,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
draggingType: null,
mode: "normal",
applyingHistory: false,
+ pendingAutoAccept: false,
})
const commentCount = createMemo(() => {
@@ -301,6 +303,12 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
}),
)
+ createEffect(
+ on(sessionKey, () => {
+ setStore("pendingAutoAccept", false)
+ }),
+ )
+
const historyComments = () => {
const byID = new Map(comments.all().map((item) => [`${item.file}\n${item.id}`, item] as const))
return prompt.context.items().flatMap((item) => {
@@ -947,10 +955,18 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
readClipboardImage: platform.readClipboardImage,
})
+ const variants = createMemo(() => ["default", ...local.model.variant.list()])
+ const accepting = createMemo(() => {
+ const id = params.id
+ if (!id) return store.pendingAutoAccept
+ return permission.isAutoAccepting(id, sdk.directory)
+ })
+
const { abort, handleSubmit } = createPromptSubmit({
info,
imageAttachments,
commentCount,
+ autoAccept: () => accepting(),
mode: () => store.mode,
working,
editor: () => editorRef,
@@ -1115,13 +1131,6 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
}
}
- const variants = createMemo(() => ["default", ...local.model.variant.list()])
- const accepting = createMemo(() => {
- const id = params.id
- if (!id) return false
- return permission.isAutoAccepting(id, sdk.directory)
- })
-
return (
<div class="relative size-full _max-h-[320px] flex flex-col gap-0">
<PromptPopover
@@ -1313,9 +1322,11 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
<Button
data-action="prompt-permissions"
variant="ghost"
- disabled={!params.id}
onClick={() => {
- if (!params.id) return
+ if (!params.id) {
+ setStore("pendingAutoAccept", (value) => !value)
+ return
+ }
permission.toggleAutoAccept(params.id, sdk.directory)
}}
classList={{
diff --git a/packages/app/src/components/prompt-input/submit.test.ts b/packages/app/src/components/prompt-input/submit.test.ts
index c3d6a9281..c633525a2 100644
--- a/packages/app/src/components/prompt-input/submit.test.ts
+++ b/packages/app/src/components/prompt-input/submit.test.ts
@@ -5,6 +5,7 @@ let createPromptSubmit: typeof import("./submit").createPromptSubmit
const createdClients: string[] = []
const createdSessions: string[] = []
+const enabledAutoAccept: Array<{ sessionID: string; directory: string }> = []
const sentShell: string[] = []
const syncedDirectories: string[] = []
@@ -69,6 +70,14 @@ beforeAll(async () => {
}),
}))
+ mock.module("@/context/permission", () => ({
+ usePermission: () => ({
+ enableAutoAccept(sessionID: string, directory: string) {
+ enabledAutoAccept.push({ sessionID, directory })
+ },
+ }),
+ }))
+
mock.module("@/context/prompt", () => ({
usePrompt: () => ({
current: () => promptValue,
@@ -145,6 +154,7 @@ beforeAll(async () => {
beforeEach(() => {
createdClients.length = 0
createdSessions.length = 0
+ enabledAutoAccept.length = 0
sentShell.length = 0
syncedDirectories.length = 0
selected = "/repo/worktree-a"
@@ -156,6 +166,7 @@ describe("prompt submit worktree selection", () => {
info: () => undefined,
imageAttachments: () => [],
commentCount: () => 0,
+ autoAccept: () => false,
mode: () => "shell",
working: () => false,
editor: () => undefined,
@@ -181,4 +192,31 @@ describe("prompt submit worktree selection", () => {
expect(sentShell).toEqual(["/repo/worktree-a", "/repo/worktree-b"])
expect(syncedDirectories).toEqual(["/repo/worktree-a", "/repo/worktree-b"])
})
+
+ test("applies auto-accept to newly created sessions", async () => {
+ const submit = createPromptSubmit({
+ info: () => undefined,
+ imageAttachments: () => [],
+ commentCount: () => 0,
+ autoAccept: () => true,
+ mode: () => "shell",
+ working: () => false,
+ editor: () => undefined,
+ queueScroll: () => undefined,
+ promptLength: (value) => value.reduce((sum, part) => sum + ("content" in part ? part.content.length : 0), 0),
+ addToHistory: () => undefined,
+ resetHistoryNavigation: () => undefined,
+ setMode: () => undefined,
+ setPopover: () => undefined,
+ newSessionWorktree: () => selected,
+ onNewSessionWorktreeReset: () => undefined,
+ onSubmit: () => undefined,
+ })
+
+ const event = { preventDefault: () => undefined } as unknown as Event
+
+ await submit.handleSubmit(event)
+
+ expect(enabledAutoAccept).toEqual([{ sessionID: "session-1", directory: "/repo/worktree-a" }])
+ })
})
diff --git a/packages/app/src/components/prompt-input/submit.ts b/packages/app/src/components/prompt-input/submit.ts
index a7ff39e09..a8c2609f4 100644
--- a/packages/app/src/components/prompt-input/submit.ts
+++ b/packages/app/src/components/prompt-input/submit.ts
@@ -8,6 +8,7 @@ import { useGlobalSync } from "@/context/global-sync"
import { useLanguage } from "@/context/language"
import { useLayout } from "@/context/layout"
import { useLocal } from "@/context/local"
+import { usePermission } from "@/context/permission"
import { type ImageAttachmentPart, type Prompt, usePrompt } from "@/context/prompt"
import { useSDK } from "@/context/sdk"
import { useSync } from "@/context/sync"
@@ -27,6 +28,7 @@ type PromptSubmitInput = {
info: Accessor<{ id: string } | undefined>
imageAttachments: Accessor<ImageAttachmentPart[]>
commentCount: Accessor<number>
+ autoAccept: Accessor<boolean>
mode: Accessor<"normal" | "shell">
working: Accessor<boolean>
editor: () => HTMLDivElement | undefined
@@ -56,6 +58,7 @@ export function createPromptSubmit(input: PromptSubmitInput) {
const sync = useSync()
const globalSync = useGlobalSync()
const local = useLocal()
+ const permission = usePermission()
const prompt = usePrompt()
const layout = useLayout()
const language = useLanguage()
@@ -140,6 +143,7 @@ export function createPromptSubmit(input: PromptSubmitInput) {
const projectDirectory = sdk.directory
const isNewSession = !params.id
+ const shouldAutoAccept = isNewSession && input.autoAccept()
const worktreeSelection = input.newSessionWorktree?.() || "main"
let sessionDirectory = projectDirectory
@@ -197,6 +201,7 @@ export function createPromptSubmit(input: PromptSubmitInput) {
return undefined
})
if (session) {
+ if (shouldAutoAccept) permission.enableAutoAccept(session.id, sessionDirectory)
layout.handoff.setTabs(base64Encode(sessionDirectory), session.id)
navigate(`/${base64Encode(sessionDirectory)}/session/${session.id}`)
}
diff --git a/packages/app/src/context/permission-auto-respond.test.ts b/packages/app/src/context/permission-auto-respond.test.ts
index 8657427d7..2e4cf4faf 100644
--- a/packages/app/src/context/permission-auto-respond.test.ts
+++ b/packages/app/src/context/permission-auto-respond.test.ts
@@ -31,13 +31,13 @@ describe("autoRespondsPermission", () => {
expect(autoRespondsPermission({ root: true }, sessions, permission("child"), "/tmp/project")).toBe(true)
})
- test("defaults to auto-accept when no lineage override exists", () => {
+ test("defaults to requiring approval when no lineage override exists", () => {
const sessions = [session({ id: "root" }), session({ id: "child", parentID: "root" }), session({ id: "other" })]
const autoAccept = {
other: true,
}
- expect(autoRespondsPermission(autoAccept, sessions, permission("child"), "/tmp/project")).toBe(true)
+ expect(autoRespondsPermission(autoAccept, sessions, permission("child"), "/tmp/project")).toBe(false)
})
test("inherits a parent session's false override", () => {
diff --git a/packages/app/src/context/permission-auto-respond.ts b/packages/app/src/context/permission-auto-respond.ts
index cabd514e7..727ccc937 100644
--- a/packages/app/src/context/permission-auto-respond.ts
+++ b/packages/app/src/context/permission-auto-respond.ts
@@ -37,5 +37,5 @@ export function autoRespondsPermission(
const value = sessionLineage(session, permission.sessionID)
.map((id) => accepted(autoAccept, id, directory))
.find((item): item is boolean => item !== undefined)
- return value ?? true
+ return value ?? false
}