diff options
| author | Adam <[email protected]> | 2026-02-26 20:36:10 -0600 |
|---|---|---|
| committer | Adam <[email protected]> | 2026-02-26 20:36:10 -0600 |
| commit | e9a7c7114184d0092c114ce7a7d9446cf0d366cc (patch) | |
| tree | 9255b5a23422d4b5ecdc9df77da17993aaab7cfd /packages/app/src/context | |
| parent | 4205fbd2aa98c6f62c8caae94e909a6048afbf53 (diff) | |
| download | opencode-e9a7c7114184d0092c114ce7a7d9446cf0d366cc.tar.gz opencode-e9a7c7114184d0092c114ce7a7d9446cf0d366cc.zip | |
fix(app): permission notifications
Diffstat (limited to 'packages/app/src/context')
| -rw-r--r-- | packages/app/src/context/permission-auto-respond.test.ts | 42 | ||||
| -rw-r--r-- | packages/app/src/context/permission-auto-respond.ts | 36 | ||||
| -rw-r--r-- | packages/app/src/context/permission.tsx | 18 |
3 files changed, 87 insertions, 9 deletions
diff --git a/packages/app/src/context/permission-auto-respond.test.ts b/packages/app/src/context/permission-auto-respond.test.ts new file mode 100644 index 000000000..1fa1ff3de --- /dev/null +++ b/packages/app/src/context/permission-auto-respond.test.ts @@ -0,0 +1,42 @@ +import { describe, expect, test } from "bun:test" +import type { PermissionRequest, Session } from "@opencode-ai/sdk/v2/client" +import { base64Encode } from "@opencode-ai/util/encode" +import { autoRespondsPermission } from "./permission-auto-respond" + +const session = (input: { id: string; parentID?: string }) => + ({ + id: input.id, + parentID: input.parentID, + }) as Session + +const permission = (sessionID: string) => + ({ + sessionID, + }) as Pick<PermissionRequest, "sessionID"> + +describe("autoRespondsPermission", () => { + test("uses a parent session's directory-scoped auto-accept", () => { + const directory = "/tmp/project" + const sessions = [session({ id: "root" }), session({ id: "child", parentID: "root" })] + const autoAccept = { + [`${base64Encode(directory)}/root`]: true, + } + + expect(autoRespondsPermission(autoAccept, sessions, permission("child"), directory)).toBe(true) + }) + + test("uses a parent session's legacy auto-accept key", () => { + const sessions = [session({ id: "root" }), session({ id: "child", parentID: "root" })] + + expect(autoRespondsPermission({ root: true }, sessions, permission("child"), "/tmp/project")).toBe(true) + }) + + test("ignores auto-accept from unrelated sessions", () => { + 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) + }) +}) diff --git a/packages/app/src/context/permission-auto-respond.ts b/packages/app/src/context/permission-auto-respond.ts new file mode 100644 index 000000000..e45e5f51c --- /dev/null +++ b/packages/app/src/context/permission-auto-respond.ts @@ -0,0 +1,36 @@ +import { base64Encode } from "@opencode-ai/util/encode" + +export function acceptKey(sessionID: string, directory?: string) { + if (!directory) return sessionID + return `${base64Encode(directory)}/${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) + return acc + }, new Map<string, string>()) + const seen = new Set([sessionID]) + const ids = [sessionID] + + for (const id of ids) { + const parentID = parent.get(id) + if (!parentID || seen.has(parentID)) continue + seen.add(parentID) + ids.push(parentID) + } + + return ids +} + +export function autoRespondsPermission( + autoAccept: Record<string, boolean>, + session: { id: string; parentID?: string }[], + permission: { sessionID: string }, + directory?: string, +) { + return sessionLineage(session, permission.sessionID).some((id) => { + const key = acceptKey(id, directory) + return autoAccept[key] ?? autoAccept[id] ?? false + }) +} diff --git a/packages/app/src/context/permission.tsx b/packages/app/src/context/permission.tsx index ccfda5e69..d63d4d568 100644 --- a/packages/app/src/context/permission.tsx +++ b/packages/app/src/context/permission.tsx @@ -6,8 +6,8 @@ import { Persist, persisted } from "@/utils/persist" import { useGlobalSDK } from "@/context/global-sdk" import { useGlobalSync } from "./global-sync" import { useParams } from "@solidjs/router" -import { base64Encode } from "@opencode-ai/util/encode" import { decode64 } from "@/utils/base64" +import { acceptKey, autoRespondsPermission } from "./permission-auto-respond" type PermissionRespondFn = (input: { sessionID: string @@ -114,16 +114,16 @@ export const { use: usePermission, provider: PermissionProvider } = createSimple }) } - function acceptKey(sessionID: string, directory?: string) { - if (!directory) return sessionID - return `${base64Encode(directory)}/${sessionID}` - } - function isAutoAccepting(sessionID: string, directory?: string) { const key = acceptKey(sessionID, directory) return store.autoAccept[key] ?? store.autoAccept[sessionID] ?? false } + function shouldAutoRespond(permission: PermissionRequest, directory?: string) { + const session = directory ? globalSync.child(directory, { bootstrap: false })[0].session : [] + return autoRespondsPermission(store.autoAccept, session, permission, directory) + } + function bumpEnableVersion(sessionID: string, directory?: string) { const key = acceptKey(sessionID, directory) const next = (enableVersion.get(key) ?? 0) + 1 @@ -136,7 +136,7 @@ export const { use: usePermission, provider: PermissionProvider } = createSimple if (event?.type !== "permission.asked") return const perm = event.properties - if (!isAutoAccepting(perm.sessionID, e.name)) return + if (!shouldAutoRespond(perm, e.name)) return respondOnce(perm, e.name) }) @@ -159,7 +159,7 @@ export const { use: usePermission, provider: PermissionProvider } = createSimple if (!isAutoAccepting(sessionID, directory)) return for (const perm of x.data ?? []) { if (!perm?.id) continue - if (perm.sessionID !== sessionID) continue + if (!shouldAutoRespond(perm, directory)) continue respondOnce(perm, directory) } }) @@ -181,7 +181,7 @@ export const { use: usePermission, provider: PermissionProvider } = createSimple ready, respond, autoResponds(permission: PermissionRequest, directory?: string) { - return isAutoAccepting(permission.sessionID, directory) + return shouldAutoRespond(permission, directory) }, isAutoAccepting, toggleAutoAccept(sessionID: string, directory: string) { |
