summaryrefslogtreecommitdiffhomepage
path: root/packages/app/src/context
diff options
context:
space:
mode:
authorAdam <[email protected]>2025-12-27 05:16:39 -0600
committerAdam <[email protected]>2025-12-27 14:43:42 -0600
commit21eba5f987482b4e2e75ab1c564815bd7b0613f4 (patch)
tree2d8cad03e54baa29d83e1e835a7ef2e64d3897e4 /packages/app/src/context
parentc523ca412747d66e0236865a4fa2481f7d50f64e (diff)
downloadopencode-21eba5f987482b4e2e75ab1c564815bd7b0613f4.tar.gz
opencode-21eba5f987482b4e2e75ab1c564815bd7b0613f4.zip
feat(desktop): permissions
Diffstat (limited to 'packages/app/src/context')
-rw-r--r--packages/app/src/context/global-sync.tsx61
-rw-r--r--packages/app/src/context/local.tsx25
2 files changed, 75 insertions, 11 deletions
diff --git a/packages/app/src/context/global-sync.tsx b/packages/app/src/context/global-sync.tsx
index c51901eb2..50c8a9d1c 100644
--- a/packages/app/src/context/global-sync.tsx
+++ b/packages/app/src/context/global-sync.tsx
@@ -15,6 +15,7 @@ import {
type McpStatus,
type LspStatus,
type VcsInfo,
+ type Permission,
createOpencodeClient,
} from "@opencode-ai/sdk/v2/client"
import { createStore, produce, reconcile } from "solid-js/store"
@@ -44,6 +45,9 @@ type State = {
todo: {
[sessionID: string]: Todo[]
}
+ permission: {
+ [sessionID: string]: Permission[]
+ }
mcp: {
[name: string]: McpStatus
}
@@ -78,6 +82,7 @@ function createGlobalSync() {
})
const children: Record<string, ReturnType<typeof createStore<State>>> = {}
+ const permissionListeners: Set<(info: { directory: string; permission: Permission }) => void> = new Set()
function child(directory: string) {
if (!directory) console.error("No directory provided")
if (!children[directory]) {
@@ -93,6 +98,7 @@ function createGlobalSync() {
session_status: {},
session_diff: {},
todo: {},
+ permission: {},
mcp: {},
lsp: [],
vcs: undefined,
@@ -163,6 +169,15 @@ function createGlobalSync() {
mcp: () => sdk.mcp.status().then((x) => setStore("mcp", x.data ?? {})),
lsp: () => sdk.lsp.status().then((x) => setStore("lsp", x.data ?? [])),
vcs: () => sdk.vcs.get().then((x) => setStore("vcs", x.data)),
+ permission: () =>
+ sdk.permission.list().then((x) => {
+ const grouped: Record<string, typeof x.data> = {}
+ for (const perm of x.data ?? []) {
+ grouped[perm.sessionID] = grouped[perm.sessionID] ?? []
+ grouped[perm.sessionID]!.push(perm)
+ }
+ setStore("permission", grouped)
+ }),
}
await Promise.all(Object.values(load).map((p) => retry(p).catch((e) => setGlobalStore("error", e))))
.then(() => setStore("ready", true))
@@ -313,6 +328,46 @@ function createGlobalSync() {
setStore("vcs", { branch: event.properties.branch })
break
}
+ case "permission.updated": {
+ const permissions = store.permission[event.properties.sessionID]
+ const isNew = !permissions || !permissions.find((p) => p.id === event.properties.id)
+ if (!permissions) {
+ setStore("permission", event.properties.sessionID, [event.properties])
+ } else {
+ const result = Binary.search(permissions, event.properties.id, (p) => p.id)
+ setStore(
+ "permission",
+ event.properties.sessionID,
+ produce((draft) => {
+ if (result.found) {
+ draft[result.index] = event.properties
+ return
+ }
+ draft.push(event.properties)
+ }),
+ )
+ }
+ if (isNew) {
+ for (const listener of permissionListeners) {
+ listener({ directory, permission: event.properties })
+ }
+ }
+ break
+ }
+ case "permission.replied": {
+ const permissions = store.permission[event.properties.sessionID]
+ if (!permissions) break
+ const result = Binary.search(permissions, event.properties.permissionID, (p) => p.id)
+ if (!result.found) break
+ setStore(
+ "permission",
+ event.properties.sessionID,
+ produce((draft) => {
+ draft.splice(result.index, 1)
+ }),
+ )
+ break
+ }
}
})
@@ -384,6 +439,12 @@ function createGlobalSync() {
project: {
loadSessions,
},
+ permission: {
+ onUpdated(listener: (info: { directory: string; permission: Permission }) => void) {
+ permissionListeners.add(listener)
+ return () => permissionListeners.delete(listener)
+ },
+ },
}
}
diff --git a/packages/app/src/context/local.tsx b/packages/app/src/context/local.tsx
index 600a0e4b1..49217b82b 100644
--- a/packages/app/src/context/local.tsx
+++ b/packages/app/src/context/local.tsx
@@ -377,17 +377,20 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({
}
const list = async (path: string) => {
- return sdk.client.file.list({ path: path + "/" }).then((x) => {
- setStore(
- "node",
- produce((draft) => {
- x.data!.forEach((node) => {
- if (node.path in draft) return
- draft[node.path] = node
- })
- }),
- )
- })
+ return sdk.client.file
+ .list({ path: path + "/" })
+ .then((x) => {
+ setStore(
+ "node",
+ produce((draft) => {
+ x.data!.forEach((node) => {
+ if (node.path in draft) return
+ draft[node.path] = node
+ })
+ }),
+ )
+ })
+ .catch(() => {})
}
const searchFiles = (query: string) => sdk.client.find.files({ query, dirs: "false" }).then((x) => x.data!)