From 21eba5f987482b4e2e75ab1c564815bd7b0613f4 Mon Sep 17 00:00:00 2001 From: Adam <2363879+adamdotdevin@users.noreply.github.com> Date: Sat, 27 Dec 2025 05:16:39 -0600 Subject: feat(desktop): permissions --- packages/app/src/pages/directory-layout.tsx | 11 +++++-- packages/app/src/pages/layout.tsx | 50 ++++++++++++++++++++++++++++- 2 files changed, 58 insertions(+), 3 deletions(-) (limited to 'packages/app/src/pages') diff --git a/packages/app/src/pages/directory-layout.tsx b/packages/app/src/pages/directory-layout.tsx index c909a373d..04f90bdcb 100644 --- a/packages/app/src/pages/directory-layout.tsx +++ b/packages/app/src/pages/directory-layout.tsx @@ -1,6 +1,6 @@ import { createMemo, Show, type ParentProps } from "solid-js" import { useParams } from "@solidjs/router" -import { SDKProvider } from "@/context/sdk" +import { SDKProvider, useSDK } from "@/context/sdk" import { SyncProvider, useSync } from "@/context/sync" import { LocalProvider } from "@/context/local" import { base64Decode } from "@opencode-ai/util/encode" @@ -18,8 +18,15 @@ export default function Layout(props: ParentProps) { {iife(() => { const sync = useSync() + const sdk = useSDK() return ( - + { + sdk.client.permission.respond(input) + }} + > {props.children} ) diff --git a/packages/app/src/pages/layout.tsx b/packages/app/src/pages/layout.tsx index 5efba6d99..538a3b840 100644 --- a/packages/app/src/pages/layout.tsx +++ b/packages/app/src/pages/layout.tsx @@ -117,6 +117,39 @@ export default function Layout(props: ParentProps) { } }) + onMount(() => { + const unsub = globalSync.permission.onUpdated(({ directory, permission }) => { + const currentDir = params.dir ? base64Decode(params.dir) : undefined + const currentSession = params.id + if (directory === currentDir && permission.sessionID === currentSession) return + const [store] = globalSync.child(directory) + const session = store.session.find((s) => s.id === permission.sessionID) + if (directory === currentDir && session?.parentID === currentSession) return + const sessionTitle = session?.title ?? "New session" + const projectName = getFilename(directory) + showToast({ + persistent: true, + icon: "checklist", + title: "Permission required", + description: `${sessionTitle} in ${projectName} needs permission`, + actions: [ + { + label: "Go to session", + onClick: () => { + navigate(`/${base64Encode(directory)}/session/${permission.sessionID}`) + }, + dismissAfter: true, + }, + { + label: "Dismiss", + onClick: "dismiss", + }, + ], + }) + }) + onCleanup(unsub) + }) + function sortSessions(a: Session, b: Session) { const now = Date.now() const oneMinuteAgo = now - 60 * 1000 @@ -454,8 +487,20 @@ export default function Layout(props: ParentProps) { const updated = createMemo(() => DateTime.fromMillis(props.session.time.updated)) const notifications = createMemo(() => notification.session.unseen(props.session.id)) const hasError = createMemo(() => notifications().some((n) => n.type === "error")) + const hasPermissions = createMemo(() => { + const store = globalSync.child(props.project.worktree)[0] + const permissions = store.permission?.[props.session.id] ?? [] + if (permissions.length > 0) return true + const childSessions = store.session.filter((s) => s.parentID === props.session.id) + for (const child of childSessions) { + const childPermissions = store.permission?.[child.id] ?? [] + if (childPermissions.length > 0) return true + } + return false + }) const isWorking = createMemo(() => { if (props.session.id === params.id) return false + if (hasPermissions()) return false const status = globalSync.child(props.project.worktree)[0].session_status[props.session.id] return status?.type === "busy" || status?.type === "retry" }) @@ -486,6 +531,9 @@ export default function Layout(props: ParentProps) { + +
+
@@ -587,7 +635,7 @@ export default function Layout(props: ParentProps) { closeProject(props.project.worktree)}> - Close Project + Close project -- cgit v1.2.3