Skip to content

Commit 7806936

Browse files
committed
fix(app): default auto-respond to false
1 parent 1cd77b1 commit 7806936

6 files changed

Lines changed: 77 additions & 12 deletions

File tree

packages/app/e2e/session/session-composer-dock.spec.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,17 @@ test("default dock shows prompt input", async ({ page, sdk, gotoSession }) => {
142142
})
143143
})
144144

145+
test("auto-accept toggle works before first submit", async ({ page, gotoSession }) => {
146+
await gotoSession()
147+
148+
const button = page.locator('[data-action="prompt-permissions"]').first()
149+
await expect(button).toBeVisible()
150+
await expect(button).toHaveAttribute("aria-pressed", "false")
151+
152+
await setAutoAccept(page, true)
153+
await setAutoAccept(page, false)
154+
})
155+
145156
test("blocked question flow unblocks after submit", async ({ page, sdk, gotoSession }) => {
146157
await withDockSession(sdk, "e2e composer dock question", async (session) => {
147158
await withDockSeed(sdk, session.id, async () => {

packages/app/src/components/prompt-input.tsx

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
243243
draggingType: "image" | "@mention" | null
244244
mode: "normal" | "shell"
245245
applyingHistory: boolean
246+
pendingAutoAccept: boolean
246247
}>({
247248
popover: null,
248249
historyIndex: -1,
@@ -251,6 +252,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
251252
draggingType: null,
252253
mode: "normal",
253254
applyingHistory: false,
255+
pendingAutoAccept: false,
254256
})
255257

256258
const commentCount = createMemo(() => {
@@ -301,6 +303,12 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
301303
}),
302304
)
303305

306+
createEffect(
307+
on(sessionKey, () => {
308+
setStore("pendingAutoAccept", false)
309+
}),
310+
)
311+
304312
const historyComments = () => {
305313
const byID = new Map(comments.all().map((item) => [`${item.file}\n${item.id}`, item] as const))
306314
return prompt.context.items().flatMap((item) => {
@@ -947,10 +955,18 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
947955
readClipboardImage: platform.readClipboardImage,
948956
})
949957

958+
const variants = createMemo(() => ["default", ...local.model.variant.list()])
959+
const accepting = createMemo(() => {
960+
const id = params.id
961+
if (!id) return store.pendingAutoAccept
962+
return permission.isAutoAccepting(id, sdk.directory)
963+
})
964+
950965
const { abort, handleSubmit } = createPromptSubmit({
951966
info,
952967
imageAttachments,
953968
commentCount,
969+
autoAccept: () => accepting(),
954970
mode: () => store.mode,
955971
working,
956972
editor: () => editorRef,
@@ -1115,13 +1131,6 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
11151131
}
11161132
}
11171133

1118-
const variants = createMemo(() => ["default", ...local.model.variant.list()])
1119-
const accepting = createMemo(() => {
1120-
const id = params.id
1121-
if (!id) return false
1122-
return permission.isAutoAccepting(id, sdk.directory)
1123-
})
1124-
11251134
return (
11261135
<div class="relative size-full _max-h-[320px] flex flex-col gap-0">
11271136
<PromptPopover
@@ -1313,9 +1322,11 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
13131322
<Button
13141323
data-action="prompt-permissions"
13151324
variant="ghost"
1316-
disabled={!params.id}
13171325
onClick={() => {
1318-
if (!params.id) return
1326+
if (!params.id) {
1327+
setStore("pendingAutoAccept", (value) => !value)
1328+
return
1329+
}
13191330
permission.toggleAutoAccept(params.id, sdk.directory)
13201331
}}
13211332
classList={{

packages/app/src/components/prompt-input/submit.test.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ let createPromptSubmit: typeof import("./submit").createPromptSubmit
55

66
const createdClients: string[] = []
77
const createdSessions: string[] = []
8+
const enabledAutoAccept: Array<{ sessionID: string; directory: string }> = []
89
const sentShell: string[] = []
910
const syncedDirectories: string[] = []
1011

@@ -69,6 +70,14 @@ beforeAll(async () => {
6970
}),
7071
}))
7172

73+
mock.module("@/context/permission", () => ({
74+
usePermission: () => ({
75+
enableAutoAccept(sessionID: string, directory: string) {
76+
enabledAutoAccept.push({ sessionID, directory })
77+
},
78+
}),
79+
}))
80+
7281
mock.module("@/context/prompt", () => ({
7382
usePrompt: () => ({
7483
current: () => promptValue,
@@ -145,6 +154,7 @@ beforeAll(async () => {
145154
beforeEach(() => {
146155
createdClients.length = 0
147156
createdSessions.length = 0
157+
enabledAutoAccept.length = 0
148158
sentShell.length = 0
149159
syncedDirectories.length = 0
150160
selected = "/repo/worktree-a"
@@ -156,6 +166,7 @@ describe("prompt submit worktree selection", () => {
156166
info: () => undefined,
157167
imageAttachments: () => [],
158168
commentCount: () => 0,
169+
autoAccept: () => false,
159170
mode: () => "shell",
160171
working: () => false,
161172
editor: () => undefined,
@@ -181,4 +192,31 @@ describe("prompt submit worktree selection", () => {
181192
expect(sentShell).toEqual(["/repo/worktree-a", "/repo/worktree-b"])
182193
expect(syncedDirectories).toEqual(["/repo/worktree-a", "/repo/worktree-b"])
183194
})
195+
196+
test("applies auto-accept to newly created sessions", async () => {
197+
const submit = createPromptSubmit({
198+
info: () => undefined,
199+
imageAttachments: () => [],
200+
commentCount: () => 0,
201+
autoAccept: () => true,
202+
mode: () => "shell",
203+
working: () => false,
204+
editor: () => undefined,
205+
queueScroll: () => undefined,
206+
promptLength: (value) => value.reduce((sum, part) => sum + ("content" in part ? part.content.length : 0), 0),
207+
addToHistory: () => undefined,
208+
resetHistoryNavigation: () => undefined,
209+
setMode: () => undefined,
210+
setPopover: () => undefined,
211+
newSessionWorktree: () => selected,
212+
onNewSessionWorktreeReset: () => undefined,
213+
onSubmit: () => undefined,
214+
})
215+
216+
const event = { preventDefault: () => undefined } as unknown as Event
217+
218+
await submit.handleSubmit(event)
219+
220+
expect(enabledAutoAccept).toEqual([{ sessionID: "session-1", directory: "/repo/worktree-a" }])
221+
})
184222
})

packages/app/src/components/prompt-input/submit.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { useGlobalSync } from "@/context/global-sync"
88
import { useLanguage } from "@/context/language"
99
import { useLayout } from "@/context/layout"
1010
import { useLocal } from "@/context/local"
11+
import { usePermission } from "@/context/permission"
1112
import { type ImageAttachmentPart, type Prompt, usePrompt } from "@/context/prompt"
1213
import { useSDK } from "@/context/sdk"
1314
import { useSync } from "@/context/sync"
@@ -27,6 +28,7 @@ type PromptSubmitInput = {
2728
info: Accessor<{ id: string } | undefined>
2829
imageAttachments: Accessor<ImageAttachmentPart[]>
2930
commentCount: Accessor<number>
31+
autoAccept: Accessor<boolean>
3032
mode: Accessor<"normal" | "shell">
3133
working: Accessor<boolean>
3234
editor: () => HTMLDivElement | undefined
@@ -56,6 +58,7 @@ export function createPromptSubmit(input: PromptSubmitInput) {
5658
const sync = useSync()
5759
const globalSync = useGlobalSync()
5860
const local = useLocal()
61+
const permission = usePermission()
5962
const prompt = usePrompt()
6063
const layout = useLayout()
6164
const language = useLanguage()
@@ -140,6 +143,7 @@ export function createPromptSubmit(input: PromptSubmitInput) {
140143

141144
const projectDirectory = sdk.directory
142145
const isNewSession = !params.id
146+
const shouldAutoAccept = isNewSession && input.autoAccept()
143147
const worktreeSelection = input.newSessionWorktree?.() || "main"
144148

145149
let sessionDirectory = projectDirectory
@@ -197,6 +201,7 @@ export function createPromptSubmit(input: PromptSubmitInput) {
197201
return undefined
198202
})
199203
if (session) {
204+
if (shouldAutoAccept) permission.enableAutoAccept(session.id, sessionDirectory)
200205
layout.handoff.setTabs(base64Encode(sessionDirectory), session.id)
201206
navigate(`/${base64Encode(sessionDirectory)}/session/${session.id}`)
202207
}

packages/app/src/context/permission-auto-respond.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,13 @@ describe("autoRespondsPermission", () => {
3131
expect(autoRespondsPermission({ root: true }, sessions, permission("child"), "/tmp/project")).toBe(true)
3232
})
3333

34-
test("defaults to auto-accept when no lineage override exists", () => {
34+
test("defaults to requiring approval when no lineage override exists", () => {
3535
const sessions = [session({ id: "root" }), session({ id: "child", parentID: "root" }), session({ id: "other" })]
3636
const autoAccept = {
3737
other: true,
3838
}
3939

40-
expect(autoRespondsPermission(autoAccept, sessions, permission("child"), "/tmp/project")).toBe(true)
40+
expect(autoRespondsPermission(autoAccept, sessions, permission("child"), "/tmp/project")).toBe(false)
4141
})
4242

4343
test("inherits a parent session's false override", () => {

packages/app/src/context/permission-auto-respond.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,5 +37,5 @@ export function autoRespondsPermission(
3737
const value = sessionLineage(session, permission.sessionID)
3838
.map((id) => accepted(autoAccept, id, directory))
3939
.find((item): item is boolean => item !== undefined)
40-
return value ?? true
40+
return value ?? false
4141
}

0 commit comments

Comments
 (0)