From 82a8ba682285aa2b8e476ca015f62f2aa7c7408e Mon Sep 17 00:00:00 2001 From: Dax Raad Date: Thu, 1 Jan 2026 16:48:50 -0500 Subject: [PATCH] sync --- .opencode/opencode.jsonc | 1 + packages/opencode/src/acp/agent.ts | 31 ++++++------ packages/opencode/src/cli/cmd/run.ts | 2 +- .../opencode/src/cli/cmd/tui/context/sync.tsx | 4 +- .../src/cli/cmd/tui/routes/session/index.tsx | 49 ++++++------------- packages/opencode/src/session/prompt.ts | 2 +- 6 files changed, 35 insertions(+), 54 deletions(-) diff --git a/.opencode/opencode.jsonc b/.opencode/opencode.jsonc index ad9925767d..f547e874dd 100644 --- a/.opencode/opencode.jsonc +++ b/.opencode/opencode.jsonc @@ -10,6 +10,7 @@ "options": {}, }, }, + "permission": "ask", "mcp": { "context7": { "type": "remote", diff --git a/packages/opencode/src/acp/agent.ts b/packages/opencode/src/acp/agent.ts index 9c5cfd15ec..bab4d2b821 100644 --- a/packages/opencode/src/acp/agent.ts +++ b/packages/opencode/src/acp/agent.ts @@ -71,19 +71,19 @@ export namespace ACP { this.config.sdk.event.subscribe({ directory }).then(async (events) => { for await (const event of events.stream) { switch (event.type) { - case "permission.updated": + case "permission.asked": try { const permission = event.properties const res = await this.connection .requestPermission({ sessionId, toolCall: { - toolCallId: permission.callID ?? permission.id, + toolCallId: permission.tool?.callID ?? permission.id, status: "pending", - title: permission.message, + title: permission.permission, rawInput: permission.metadata, - kind: toToolKind(permission.type), - locations: toLocations(permission.type, permission.metadata), + kind: toToolKind(permission.permission), + locations: toLocations(permission.permission, permission.metadata), }, options, }) @@ -93,28 +93,25 @@ export namespace ACP { permissionID: permission.id, sessionID: permission.sessionID, }) - await this.config.sdk.permission.respond({ - sessionID: permission.sessionID, - permissionID: permission.id, - response: "reject", + await this.config.sdk.permission.reply({ + requestID: permission.id, + reply: "reject", directory, }) return }) if (!res) return if (res.outcome.outcome !== "selected") { - await this.config.sdk.permission.respond({ - sessionID: permission.sessionID, - permissionID: permission.id, - response: "reject", + await this.config.sdk.permission.reply({ + requestID: permission.id, + reply: "reject", directory, }) return } - await this.config.sdk.permission.respond({ - sessionID: permission.sessionID, - permissionID: permission.id, - response: res.outcome.optionId as "once" | "always" | "reject", + await this.config.sdk.permission.reply({ + requestID: permission.id, + reply: res.outcome.optionId as "once" | "always" | "reject", directory, }) } catch (err) { diff --git a/packages/opencode/src/cli/cmd/run.ts b/packages/opencode/src/cli/cmd/run.ts index 4a3506e25f..876b64bd82 100644 --- a/packages/opencode/src/cli/cmd/run.ts +++ b/packages/opencode/src/cli/cmd/run.ts @@ -202,7 +202,7 @@ export const RunCommand = cmd({ break } - if (event.type === "permission.next.asked") { + if (event.type === "permission.asked") { const permission = event.properties if (permission.sessionID !== sessionID) continue const result = await select({ diff --git a/packages/opencode/src/cli/cmd/tui/context/sync.tsx b/packages/opencode/src/cli/cmd/tui/context/sync.tsx index 7d67f3e76a..cc4e9c69ae 100644 --- a/packages/opencode/src/cli/cmd/tui/context/sync.tsx +++ b/packages/opencode/src/cli/cmd/tui/context/sync.tsx @@ -97,7 +97,7 @@ export const { use: useSync, provider: SyncProvider } = createSimpleContext({ sdk.event.listen((e) => { const event = e.details switch (event.type) { - case "permission.next.replied": { + case "permission.replied": { const requests = store.permission[event.properties.sessionID] if (!requests) break const match = Binary.search(requests, event.properties.requestID, (r) => r.id) @@ -112,7 +112,7 @@ export const { use: useSync, provider: SyncProvider } = createSimpleContext({ break } - case "permission.next.asked": { + case "permission.asked": { const request = event.properties const requests = store.permission[request.sessionID] if (!requests) { diff --git a/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx b/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx index 287c4ea5ae..8a6c5cdd25 100644 --- a/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx +++ b/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx @@ -107,8 +107,17 @@ export function Session() { const { theme } = useTheme() const promptRef = usePromptRef() const session = createMemo(() => sync.session.get(route.sessionID)!) + const children = createMemo(() => { + const parentID = session()?.parentID ?? session()?.id + return sync.data.session + .filter((x) => x.parentID === parentID || x.id === parentID) + .toSorted((a, b) => (a.id < b.id ? -1 : a.id > b.id ? 1 : 0)) + }) const messages = createMemo(() => sync.data.message[route.sessionID] ?? []) - const permissions = createMemo(() => sync.data.permission[route.sessionID] ?? []) + const permissions = createMemo(() => { + if (session().parentID) return sync.data.permission[route.sessionID] ?? [] + return children().flatMap((x) => sync.data.permission[x.id] ?? []) + }) const pending = createMemo(() => { return messages().findLast((x) => x.role === "assistant" && !x.time.completed)?.id @@ -176,28 +185,6 @@ export function Session() { } }) - // Auto-navigate to whichever session currently needs permission input - createEffect(() => { - const currentSession = session() - if (!currentSession) return - const currentPermissions = permissions() - let targetID = currentPermissions.length > 0 ? currentSession.id : undefined - - if (!targetID) { - const child = sync.data.session.find( - (x) => x.parentID === currentSession.id && (sync.data.permission[x.id]?.length ?? 0) > 0, - ) - if (child) targetID = child.id - } - - if (targetID && targetID !== currentSession.id) { - navigate({ - type: "session", - sessionID: targetID, - }) - } - }) - let scroll: ScrollBoxRenderable let prompt: PromptRef const keybind = useKeybind() @@ -257,18 +244,14 @@ export function Session() { const local = useLocal() function moveChild(direction: number) { - const parentID = session()?.parentID ?? session()?.id - let children = sync.data.session - .filter((x) => x.parentID === parentID || x.id === parentID) - .toSorted((a, b) => (a.id < b.id ? -1 : a.id > b.id ? 1 : 0)) - if (children.length === 1) return - let next = children.findIndex((x) => x.id === session()?.id) + direction - if (next >= children.length) next = 0 - if (next < 0) next = children.length - 1 - if (children[next]) { + if (children().length === 1) return + let next = children().findIndex((x) => x.id === session()?.id) + direction + if (next >= children().length) next = 0 + if (next < 0) next = children().length - 1 + if (children()[next]) { navigate({ type: "session", - sessionID: children[next].id, + sessionID: children()[next].id, }) } } diff --git a/packages/opencode/src/session/prompt.ts b/packages/opencode/src/session/prompt.ts index 1947f2e998..d4fef6f7a1 100644 --- a/packages/opencode/src/session/prompt.ts +++ b/packages/opencode/src/session/prompt.ts @@ -646,7 +646,7 @@ export namespace SessionPrompt { async ask(req) { await PermissionNext.ask({ ...req, - sessionID: input.session.parentID ?? input.session.id, + sessionID: input.session.id, tool: { messageID: input.processor.message.id, callID: options.toolCallId }, ruleset: PermissionNext.merge(input.agent.permission, input.session.permission ?? []), })