diff options
| -rw-r--r-- | packages/app/src/components/prompt-input.tsx | 72 | ||||
| -rw-r--r-- | packages/app/src/context/permission-auto-respond.test.ts | 25 | ||||
| -rw-r--r-- | packages/app/src/context/permission-auto-respond.ts | 13 | ||||
| -rw-r--r-- | packages/app/src/context/permission.tsx | 9 |
4 files changed, 74 insertions, 45 deletions
diff --git a/packages/app/src/components/prompt-input.tsx b/packages/app/src/components/prompt-input.tsx index 85aa16384..3ba3763b8 100644 --- a/packages/app/src/components/prompt-input.tsx +++ b/packages/app/src/components/prompt-input.tsx @@ -1310,43 +1310,45 @@ export const PromptInput: Component<PromptInputProps> = (props) => { </div> </div> - <Show when={store.mode === "normal" && permission.permissionsEnabled() && params.id}> - <div class="pointer-events-none absolute bottom-2 left-2"> - <div class="pointer-events-auto"> - <TooltipKeybind - placement="top" - gutter={8} - title={language.t( - accepting() ? "command.permissions.autoaccept.disable" : "command.permissions.autoaccept.enable", - )} - keybind={command.keybind("permissions.autoaccept")} + <div class="pointer-events-none absolute bottom-2 left-2"> + <div class="pointer-events-auto"> + <TooltipKeybind + placement="top" + gutter={8} + title={language.t( + accepting() ? "command.permissions.autoaccept.disable" : "command.permissions.autoaccept.enable", + )} + keybind={command.keybind("permissions.autoaccept")} + > + <Button + data-action="prompt-permissions" + variant="ghost" + disabled={!params.id} + onClick={() => { + if (!params.id) return + permission.toggleAutoAccept(params.id, sdk.directory) + }} + classList={{ + "size-6 flex items-center justify-center": true, + "text-text-base": !accepting(), + "hover:bg-surface-success-base": accepting(), + }} + aria-label={ + accepting() + ? language.t("command.permissions.autoaccept.disable") + : language.t("command.permissions.autoaccept.enable") + } + aria-pressed={accepting()} > - <Button - data-action="prompt-permissions" - variant="ghost" - onClick={() => permission.toggleAutoAccept(params.id!, sdk.directory)} - classList={{ - "_hidden group-hover/prompt-input:flex size-6 items-center justify-center": true, - "text-text-base": !accepting(), - "hover:bg-surface-success-base": accepting(), - }} - aria-label={ - accepting() - ? language.t("command.permissions.autoaccept.disable") - : language.t("command.permissions.autoaccept.enable") - } - aria-pressed={accepting()} - > - <Icon - name="chevron-double-right" - size="small" - classList={{ "text-icon-success-base": accepting() }} - /> - </Button> - </TooltipKeybind> - </div> + <Icon + name="chevron-double-right" + size="small" + classList={{ "text-icon-success-base": accepting() }} + /> + </Button> + </TooltipKeybind> </div> - </Show> + </div> </div> </DockShellForm> <Show when={store.mode === "normal" || store.mode === "shell"}> diff --git a/packages/app/src/context/permission-auto-respond.test.ts b/packages/app/src/context/permission-auto-respond.test.ts index 1fa1ff3de..8657427d7 100644 --- a/packages/app/src/context/permission-auto-respond.test.ts +++ b/packages/app/src/context/permission-auto-respond.test.ts @@ -31,12 +31,33 @@ describe("autoRespondsPermission", () => { expect(autoRespondsPermission({ root: true }, sessions, permission("child"), "/tmp/project")).toBe(true) }) - test("ignores auto-accept from unrelated sessions", () => { + test("defaults to auto-accept 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(false) + expect(autoRespondsPermission(autoAccept, sessions, permission("child"), "/tmp/project")).toBe(true) + }) + + test("inherits a parent session's false override", () => { + const directory = "/tmp/project" + const sessions = [session({ id: "root" }), session({ id: "child", parentID: "root" })] + const autoAccept = { + [`${base64Encode(directory)}/root`]: false, + } + + expect(autoRespondsPermission(autoAccept, sessions, permission("child"), directory)).toBe(false) + }) + + test("prefers a child override over parent override", () => { + const directory = "/tmp/project" + const sessions = [session({ id: "root" }), session({ id: "child", parentID: "root" })] + const autoAccept = { + [`${base64Encode(directory)}/root`]: false, + [`${base64Encode(directory)}/child`]: true, + } + + expect(autoRespondsPermission(autoAccept, sessions, permission("child"), directory)).toBe(true) }) }) diff --git a/packages/app/src/context/permission-auto-respond.ts b/packages/app/src/context/permission-auto-respond.ts index e45e5f51c..cabd514e7 100644 --- a/packages/app/src/context/permission-auto-respond.ts +++ b/packages/app/src/context/permission-auto-respond.ts @@ -5,6 +5,11 @@ export function acceptKey(sessionID: string, directory?: string) { return `${base64Encode(directory)}/${sessionID}` } +function accepted(autoAccept: Record<string, boolean>, sessionID: string, directory?: string) { + const key = acceptKey(sessionID, directory) + return autoAccept[key] ?? autoAccept[sessionID] +} + function sessionLineage(session: { id: string; parentID?: string }[], sessionID: string) { const parent = session.reduce((acc, item) => { if (item.parentID) acc.set(item.id, item.parentID) @@ -29,8 +34,8 @@ export function autoRespondsPermission( permission: { sessionID: string }, directory?: string, ) { - return sessionLineage(session, permission.sessionID).some((id) => { - const key = acceptKey(id, directory) - return autoAccept[key] ?? autoAccept[id] ?? false - }) + const value = sessionLineage(session, permission.sessionID) + .map((id) => accepted(autoAccept, id, directory)) + .find((item): item is boolean => item !== undefined) + return value ?? true } diff --git a/packages/app/src/context/permission.tsx b/packages/app/src/context/permission.tsx index d63d4d568..73ee08c9a 100644 --- a/packages/app/src/context/permission.tsx +++ b/packages/app/src/context/permission.tsx @@ -115,8 +115,8 @@ export const { use: usePermission, provider: PermissionProvider } = createSimple } function isAutoAccepting(sessionID: string, directory?: string) { - const key = acceptKey(sessionID, directory) - return store.autoAccept[key] ?? store.autoAccept[sessionID] ?? false + const session = directory ? globalSync.child(directory, { bootstrap: false })[0].session : [] + return autoRespondsPermission(store.autoAccept, session, { sessionID }, directory) } function shouldAutoRespond(permission: PermissionRequest, directory?: string) { @@ -168,10 +168,11 @@ export const { use: usePermission, provider: PermissionProvider } = createSimple function disable(sessionID: string, directory?: string) { bumpEnableVersion(sessionID, directory) - const key = directory ? acceptKey(sessionID, directory) : undefined + const key = directory ? acceptKey(sessionID, directory) : sessionID setStore( produce((draft) => { - if (key) delete draft.autoAccept[key] + draft.autoAccept[key] = false + if (!directory) return delete draft.autoAccept[sessionID] }), ) |
