mirror of
https://github.com/aljazceru/opencode.git
synced 2025-12-20 01:04:22 +01:00
wip: refactor permissions
This commit is contained in:
@@ -28,5 +28,9 @@
|
|||||||
"type": "local",
|
"type": "local",
|
||||||
"command": ["opencode", "x", "@h1deya/mcp-server-weather"]
|
"command": ["opencode", "x", "@h1deya/mcp-server-weather"]
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"permission": {
|
||||||
|
"edit": "ask",
|
||||||
|
"bash": "ask"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ export namespace Identifier {
|
|||||||
const prefixes = {
|
const prefixes = {
|
||||||
session: "ses",
|
session: "ses",
|
||||||
message: "msg",
|
message: "msg",
|
||||||
|
permission: "per",
|
||||||
user: "usr",
|
user: "usr",
|
||||||
part: "prt",
|
part: "prt",
|
||||||
} as const
|
} as const
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { z } from "zod"
|
|||||||
import { Bus } from "../bus"
|
import { Bus } from "../bus"
|
||||||
import { Log } from "../util/log"
|
import { Log } from "../util/log"
|
||||||
import { Installation } from "../installation"
|
import { Installation } from "../installation"
|
||||||
|
import { Identifier } from "../id/id"
|
||||||
|
|
||||||
export namespace Permission {
|
export namespace Permission {
|
||||||
const log = Log.create({ service: "permission" })
|
const log = Log.create({ service: "permission" })
|
||||||
@@ -10,9 +11,11 @@ export namespace Permission {
|
|||||||
export const Info = z
|
export const Info = z
|
||||||
.object({
|
.object({
|
||||||
id: z.string(),
|
id: z.string(),
|
||||||
|
type: z.string(),
|
||||||
|
pattern: z.string().optional(),
|
||||||
sessionID: z.string(),
|
sessionID: z.string(),
|
||||||
messageID: z.string(),
|
messageID: z.string(),
|
||||||
toolCallID: z.string().optional(),
|
callID: z.string().optional(),
|
||||||
title: z.string(),
|
title: z.string(),
|
||||||
metadata: z.record(z.any()),
|
metadata: z.record(z.any()),
|
||||||
time: z.object({
|
time: z.object({
|
||||||
@@ -55,18 +58,19 @@ export namespace Permission {
|
|||||||
async (state) => {
|
async (state) => {
|
||||||
for (const pending of Object.values(state.pending)) {
|
for (const pending of Object.values(state.pending)) {
|
||||||
for (const item of Object.values(pending)) {
|
for (const item of Object.values(pending)) {
|
||||||
item.reject(new RejectedError(item.info.sessionID, item.info.id, item.info.toolCallID))
|
item.reject(new RejectedError(item.info.sessionID, item.info.id, item.info.callID))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
export function ask(input: {
|
export function ask(input: {
|
||||||
id: Info["id"]
|
type: Info["type"]
|
||||||
|
title: Info["title"]
|
||||||
|
pattern?: Info["pattern"]
|
||||||
|
callID?: Info["callID"]
|
||||||
sessionID: Info["sessionID"]
|
sessionID: Info["sessionID"]
|
||||||
messageID: Info["messageID"]
|
messageID: Info["messageID"]
|
||||||
toolCallID?: Info["toolCallID"]
|
|
||||||
title: Info["title"]
|
|
||||||
metadata: Info["metadata"]
|
metadata: Info["metadata"]
|
||||||
}) {
|
}) {
|
||||||
// TODO: dax, remove this when you're happy with permissions
|
// TODO: dax, remove this when you're happy with permissions
|
||||||
@@ -75,24 +79,16 @@ export namespace Permission {
|
|||||||
const { pending, approved } = state()
|
const { pending, approved } = state()
|
||||||
log.info("asking", {
|
log.info("asking", {
|
||||||
sessionID: input.sessionID,
|
sessionID: input.sessionID,
|
||||||
permissionID: input.id,
|
|
||||||
messageID: input.messageID,
|
messageID: input.messageID,
|
||||||
toolCallID: input.toolCallID,
|
toolCallID: input.callID,
|
||||||
})
|
})
|
||||||
if (approved[input.sessionID]?.[input.id]) {
|
if (approved[input.sessionID]?.[input.pattern ?? input.type]) return
|
||||||
log.info("previously approved", {
|
|
||||||
sessionID: input.sessionID,
|
|
||||||
permissionID: input.id,
|
|
||||||
messageID: input.messageID,
|
|
||||||
toolCallID: input.toolCallID,
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const info: Info = {
|
const info: Info = {
|
||||||
id: input.id,
|
id: Identifier.ascending("permission"),
|
||||||
|
type: input.type,
|
||||||
sessionID: input.sessionID,
|
sessionID: input.sessionID,
|
||||||
messageID: input.messageID,
|
messageID: input.messageID,
|
||||||
toolCallID: input.toolCallID,
|
callID: input.callID,
|
||||||
title: input.title,
|
title: input.title,
|
||||||
metadata: input.metadata,
|
metadata: input.metadata,
|
||||||
time: {
|
time: {
|
||||||
@@ -101,18 +97,11 @@ export namespace Permission {
|
|||||||
}
|
}
|
||||||
pending[input.sessionID] = pending[input.sessionID] || {}
|
pending[input.sessionID] = pending[input.sessionID] || {}
|
||||||
return new Promise<void>((resolve, reject) => {
|
return new Promise<void>((resolve, reject) => {
|
||||||
pending[input.sessionID][input.id] = {
|
pending[input.sessionID][info.id] = {
|
||||||
info,
|
info,
|
||||||
resolve,
|
resolve,
|
||||||
reject,
|
reject,
|
||||||
}
|
}
|
||||||
// setTimeout(() => {
|
|
||||||
// respond({
|
|
||||||
// sessionID: input.sessionID,
|
|
||||||
// permissionID: input.id,
|
|
||||||
// response: "always",
|
|
||||||
// })
|
|
||||||
// }, 1000)
|
|
||||||
Bus.publish(Event.Updated, info)
|
Bus.publish(Event.Updated, info)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -127,7 +116,7 @@ export namespace Permission {
|
|||||||
if (!match) return
|
if (!match) return
|
||||||
delete pending[input.sessionID][input.permissionID]
|
delete pending[input.sessionID][input.permissionID]
|
||||||
if (input.response === "reject") {
|
if (input.response === "reject") {
|
||||||
match.reject(new RejectedError(input.sessionID, input.permissionID, match.info.toolCallID))
|
match.reject(new RejectedError(input.sessionID, input.permissionID, match.info.callID))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
match.resolve()
|
match.resolve()
|
||||||
|
|||||||
@@ -108,10 +108,11 @@ export const BashTool = Tool.define("bash", {
|
|||||||
const cfg = await Config.get()
|
const cfg = await Config.get()
|
||||||
if (cfg.permission?.bash === "ask")
|
if (cfg.permission?.bash === "ask")
|
||||||
await Permission.ask({
|
await Permission.ask({
|
||||||
id: "bash",
|
type: "bash",
|
||||||
|
pattern: params.command.split(" ").slice(0, 2).join(" ").trim(),
|
||||||
sessionID: ctx.sessionID,
|
sessionID: ctx.sessionID,
|
||||||
messageID: ctx.messageID,
|
messageID: ctx.messageID,
|
||||||
toolCallID: ctx.toolCallID,
|
callID: ctx.toolCallID,
|
||||||
title: "Run this command: " + params.command,
|
title: "Run this command: " + params.command,
|
||||||
metadata: {
|
metadata: {
|
||||||
command: params.command,
|
command: params.command,
|
||||||
|
|||||||
@@ -50,10 +50,10 @@ export const EditTool = Tool.define("edit", {
|
|||||||
diff = trimDiff(createTwoFilesPatch(filePath, filePath, contentOld, contentNew))
|
diff = trimDiff(createTwoFilesPatch(filePath, filePath, contentOld, contentNew))
|
||||||
if (cfg.permission?.edit === "ask") {
|
if (cfg.permission?.edit === "ask") {
|
||||||
await Permission.ask({
|
await Permission.ask({
|
||||||
id: "edit",
|
type: "edit",
|
||||||
sessionID: ctx.sessionID,
|
sessionID: ctx.sessionID,
|
||||||
messageID: ctx.messageID,
|
messageID: ctx.messageID,
|
||||||
toolCallID: ctx.toolCallID,
|
callID: ctx.toolCallID,
|
||||||
title: "Edit this file: " + filePath,
|
title: "Edit this file: " + filePath,
|
||||||
metadata: {
|
metadata: {
|
||||||
filePath,
|
filePath,
|
||||||
@@ -79,10 +79,10 @@ export const EditTool = Tool.define("edit", {
|
|||||||
diff = trimDiff(createTwoFilesPatch(filePath, filePath, contentOld, contentNew))
|
diff = trimDiff(createTwoFilesPatch(filePath, filePath, contentOld, contentNew))
|
||||||
if (cfg.permission?.edit === "ask") {
|
if (cfg.permission?.edit === "ask") {
|
||||||
await Permission.ask({
|
await Permission.ask({
|
||||||
id: "edit",
|
type: "edit",
|
||||||
sessionID: ctx.sessionID,
|
sessionID: ctx.sessionID,
|
||||||
messageID: ctx.messageID,
|
messageID: ctx.messageID,
|
||||||
toolCallID: ctx.toolCallID,
|
callID: ctx.toolCallID,
|
||||||
title: "Edit this file: " + filePath,
|
title: "Edit this file: " + filePath,
|
||||||
metadata: {
|
metadata: {
|
||||||
filePath,
|
filePath,
|
||||||
|
|||||||
@@ -31,10 +31,10 @@ export const WriteTool = Tool.define("write", {
|
|||||||
const cfg = await Config.get()
|
const cfg = await Config.get()
|
||||||
if (cfg.permission?.edit === "ask")
|
if (cfg.permission?.edit === "ask")
|
||||||
await Permission.ask({
|
await Permission.ask({
|
||||||
id: "write",
|
type: "write",
|
||||||
sessionID: ctx.sessionID,
|
sessionID: ctx.sessionID,
|
||||||
messageID: ctx.messageID,
|
messageID: ctx.messageID,
|
||||||
toolCallID: ctx.toolCallID,
|
callID: ctx.toolCallID,
|
||||||
title: exists ? "Overwrite this file: " + filepath : "Create new file: " + filepath,
|
title: exists ? "Overwrite this file: " + filepath : "Create new file: " + filepath,
|
||||||
metadata: {
|
metadata: {
|
||||||
filePath: filepath,
|
filePath: filepath,
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
configured_endpoints: 26
|
configured_endpoints: 28
|
||||||
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/opencode%2Fopencode-5bf6a39123d248d306490c1dee61b46ba113ea2c415a4de1a631c76462769c49.yml
|
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/opencode%2Fopencode-3fa00e84a92784c0e12cf47a49cf5ac4eb5556b5b3ad8769ad7b4e7e1bf1b01a.yml
|
||||||
openapi_spec_hash: 3c5b25f121429281275ffd70c9d5cfe4
|
openapi_spec_hash: 5f98ce812d7feb00e6c2eb7a15dd8887
|
||||||
config_hash: 1ae82c93499b9f0b9ba828b8919f9cb3
|
config_hash: 7707d73ebbd7ad7042ab70466b39348d
|
||||||
|
|||||||
@@ -103,6 +103,7 @@ Response Types:
|
|||||||
- <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#ToolStatePending">ToolStatePending</a>
|
- <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#ToolStatePending">ToolStatePending</a>
|
||||||
- <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#ToolStateRunning">ToolStateRunning</a>
|
- <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#ToolStateRunning">ToolStateRunning</a>
|
||||||
- <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#UserMessage">UserMessage</a>
|
- <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#UserMessage">UserMessage</a>
|
||||||
|
- <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionMessageResponse">SessionMessageResponse</a>
|
||||||
- <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionMessagesResponse">SessionMessagesResponse</a>
|
- <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionMessagesResponse">SessionMessagesResponse</a>
|
||||||
|
|
||||||
Methods:
|
Methods:
|
||||||
@@ -113,6 +114,7 @@ Methods:
|
|||||||
- <code title="post /session/{id}/abort">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Abort">Abort</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>) (<a href="https://pkg.go.dev/builtin#bool">bool</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
- <code title="post /session/{id}/abort">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Abort">Abort</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>) (<a href="https://pkg.go.dev/builtin#bool">bool</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||||
- <code title="post /session/{id}/message">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Chat">Chat</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>, body <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionChatParams">SessionChatParams</a>) (<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#AssistantMessage">AssistantMessage</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
- <code title="post /session/{id}/message">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Chat">Chat</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>, body <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionChatParams">SessionChatParams</a>) (<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#AssistantMessage">AssistantMessage</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||||
- <code title="post /session/{id}/init">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Init">Init</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>, body <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionInitParams">SessionInitParams</a>) (<a href="https://pkg.go.dev/builtin#bool">bool</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
- <code title="post /session/{id}/init">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Init">Init</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>, body <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionInitParams">SessionInitParams</a>) (<a href="https://pkg.go.dev/builtin#bool">bool</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||||
|
- <code title="get /session/{id}/message/{messageID}">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Message">Message</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>, messageID <a href="https://pkg.go.dev/builtin#string">string</a>) (<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionMessageResponse">SessionMessageResponse</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||||
- <code title="get /session/{id}/message">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Messages">Messages</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>) ([]<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionMessagesResponse">SessionMessagesResponse</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
- <code title="get /session/{id}/message">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Messages">Messages</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>) ([]<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionMessagesResponse">SessionMessagesResponse</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||||
- <code title="post /session/{id}/revert">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Revert">Revert</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>, body <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionRevertParams">SessionRevertParams</a>) (<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#Session">Session</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
- <code title="post /session/{id}/revert">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Revert">Revert</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>, body <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionRevertParams">SessionRevertParams</a>) (<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#Session">Session</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||||
- <code title="post /session/{id}/share">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Share">Share</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>) (<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#Session">Session</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
- <code title="post /session/{id}/share">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Share">Share</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>) (<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#Session">Session</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||||
@@ -120,6 +122,16 @@ Methods:
|
|||||||
- <code title="post /session/{id}/unrevert">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Unrevert">Unrevert</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>) (<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#Session">Session</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
- <code title="post /session/{id}/unrevert">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Unrevert">Unrevert</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>) (<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#Session">Session</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||||
- <code title="delete /session/{id}/share">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Unshare">Unshare</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>) (<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#Session">Session</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
- <code title="delete /session/{id}/share">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Unshare">Unshare</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>) (<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#Session">Session</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||||
|
|
||||||
|
## Permissions
|
||||||
|
|
||||||
|
Response Types:
|
||||||
|
|
||||||
|
- <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#Permission">Permission</a>
|
||||||
|
|
||||||
|
Methods:
|
||||||
|
|
||||||
|
- <code title="post /session/{id}/permissions/{permissionID}">client.Session.Permissions.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionPermissionService.Respond">Respond</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>, permissionID <a href="https://pkg.go.dev/builtin#string">string</a>, body <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionPermissionRespondParams">SessionPermissionRespondParams</a>) (<a href="https://pkg.go.dev/builtin#bool">bool</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
|
||||||
|
|
||||||
# Tui
|
# Tui
|
||||||
|
|
||||||
Methods:
|
Methods:
|
||||||
|
|||||||
@@ -54,8 +54,7 @@ type EventListResponse struct {
|
|||||||
// [EventListResponseEventMessageRemovedProperties],
|
// [EventListResponseEventMessageRemovedProperties],
|
||||||
// [EventListResponseEventMessagePartUpdatedProperties],
|
// [EventListResponseEventMessagePartUpdatedProperties],
|
||||||
// [EventListResponseEventMessagePartRemovedProperties],
|
// [EventListResponseEventMessagePartRemovedProperties],
|
||||||
// [EventListResponseEventStorageWriteProperties],
|
// [EventListResponseEventStorageWriteProperties], [Permission],
|
||||||
// [EventListResponseEventPermissionUpdatedProperties],
|
|
||||||
// [EventListResponseEventFileEditedProperties],
|
// [EventListResponseEventFileEditedProperties],
|
||||||
// [EventListResponseEventSessionUpdatedProperties],
|
// [EventListResponseEventSessionUpdatedProperties],
|
||||||
// [EventListResponseEventSessionDeletedProperties],
|
// [EventListResponseEventSessionDeletedProperties],
|
||||||
@@ -643,7 +642,7 @@ func (r EventListResponseEventStorageWriteType) IsKnown() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type EventListResponseEventPermissionUpdated struct {
|
type EventListResponseEventPermissionUpdated struct {
|
||||||
Properties EventListResponseEventPermissionUpdatedProperties `json:"properties,required"`
|
Properties Permission `json:"properties,required"`
|
||||||
Type EventListResponseEventPermissionUpdatedType `json:"type,required"`
|
Type EventListResponseEventPermissionUpdatedType `json:"type,required"`
|
||||||
JSON eventListResponseEventPermissionUpdatedJSON `json:"-"`
|
JSON eventListResponseEventPermissionUpdatedJSON `json:"-"`
|
||||||
}
|
}
|
||||||
@@ -667,56 +666,6 @@ func (r eventListResponseEventPermissionUpdatedJSON) RawJSON() string {
|
|||||||
|
|
||||||
func (r EventListResponseEventPermissionUpdated) implementsEventListResponse() {}
|
func (r EventListResponseEventPermissionUpdated) implementsEventListResponse() {}
|
||||||
|
|
||||||
type EventListResponseEventPermissionUpdatedProperties struct {
|
|
||||||
ID string `json:"id,required"`
|
|
||||||
Metadata map[string]interface{} `json:"metadata,required"`
|
|
||||||
SessionID string `json:"sessionID,required"`
|
|
||||||
Time EventListResponseEventPermissionUpdatedPropertiesTime `json:"time,required"`
|
|
||||||
Title string `json:"title,required"`
|
|
||||||
JSON eventListResponseEventPermissionUpdatedPropertiesJSON `json:"-"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// eventListResponseEventPermissionUpdatedPropertiesJSON contains the JSON metadata
|
|
||||||
// for the struct [EventListResponseEventPermissionUpdatedProperties]
|
|
||||||
type eventListResponseEventPermissionUpdatedPropertiesJSON struct {
|
|
||||||
ID apijson.Field
|
|
||||||
Metadata apijson.Field
|
|
||||||
SessionID apijson.Field
|
|
||||||
Time apijson.Field
|
|
||||||
Title apijson.Field
|
|
||||||
raw string
|
|
||||||
ExtraFields map[string]apijson.Field
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *EventListResponseEventPermissionUpdatedProperties) UnmarshalJSON(data []byte) (err error) {
|
|
||||||
return apijson.UnmarshalRoot(data, r)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r eventListResponseEventPermissionUpdatedPropertiesJSON) RawJSON() string {
|
|
||||||
return r.raw
|
|
||||||
}
|
|
||||||
|
|
||||||
type EventListResponseEventPermissionUpdatedPropertiesTime struct {
|
|
||||||
Created float64 `json:"created,required"`
|
|
||||||
JSON eventListResponseEventPermissionUpdatedPropertiesTimeJSON `json:"-"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// eventListResponseEventPermissionUpdatedPropertiesTimeJSON contains the JSON
|
|
||||||
// metadata for the struct [EventListResponseEventPermissionUpdatedPropertiesTime]
|
|
||||||
type eventListResponseEventPermissionUpdatedPropertiesTimeJSON struct {
|
|
||||||
Created apijson.Field
|
|
||||||
raw string
|
|
||||||
ExtraFields map[string]apijson.Field
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *EventListResponseEventPermissionUpdatedPropertiesTime) UnmarshalJSON(data []byte) (err error) {
|
|
||||||
return apijson.UnmarshalRoot(data, r)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r eventListResponseEventPermissionUpdatedPropertiesTimeJSON) RawJSON() string {
|
|
||||||
return r.raw
|
|
||||||
}
|
|
||||||
|
|
||||||
type EventListResponseEventPermissionUpdatedType string
|
type EventListResponseEventPermissionUpdatedType string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import (
|
|||||||
// the [NewSessionService] method instead.
|
// the [NewSessionService] method instead.
|
||||||
type SessionService struct {
|
type SessionService struct {
|
||||||
Options []option.RequestOption
|
Options []option.RequestOption
|
||||||
|
Permissions *SessionPermissionService
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewSessionService generates a new service that applies the given options to each
|
// NewSessionService generates a new service that applies the given options to each
|
||||||
@@ -33,6 +34,7 @@ type SessionService struct {
|
|||||||
func NewSessionService(opts ...option.RequestOption) (r *SessionService) {
|
func NewSessionService(opts ...option.RequestOption) (r *SessionService) {
|
||||||
r = &SessionService{}
|
r = &SessionService{}
|
||||||
r.Options = opts
|
r.Options = opts
|
||||||
|
r.Permissions = NewSessionPermissionService(opts...)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,6 +102,22 @@ func (r *SessionService) Init(ctx context.Context, id string, body SessionInitPa
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get a message from a session
|
||||||
|
func (r *SessionService) Message(ctx context.Context, id string, messageID string, opts ...option.RequestOption) (res *SessionMessageResponse, err error) {
|
||||||
|
opts = append(r.Options[:], opts...)
|
||||||
|
if id == "" {
|
||||||
|
err = errors.New("missing required id parameter")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if messageID == "" {
|
||||||
|
err = errors.New("missing required messageID parameter")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
path := fmt.Sprintf("session/%s/message/%s", id, messageID)
|
||||||
|
err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, nil, &res, opts...)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// List messages for a session
|
// List messages for a session
|
||||||
func (r *SessionService) Messages(ctx context.Context, id string, opts ...option.RequestOption) (res *[]SessionMessagesResponse, err error) {
|
func (r *SessionService) Messages(ctx context.Context, id string, opts ...option.RequestOption) (res *[]SessionMessagesResponse, err error) {
|
||||||
opts = append(r.Options[:], opts...)
|
opts = append(r.Options[:], opts...)
|
||||||
@@ -2012,6 +2030,29 @@ func (r userMessageTimeJSON) RawJSON() string {
|
|||||||
return r.raw
|
return r.raw
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SessionMessageResponse struct {
|
||||||
|
Info Message `json:"info,required"`
|
||||||
|
Parts []Part `json:"parts,required"`
|
||||||
|
JSON sessionMessageResponseJSON `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// sessionMessageResponseJSON contains the JSON metadata for the struct
|
||||||
|
// [SessionMessageResponse]
|
||||||
|
type sessionMessageResponseJSON struct {
|
||||||
|
Info apijson.Field
|
||||||
|
Parts apijson.Field
|
||||||
|
raw string
|
||||||
|
ExtraFields map[string]apijson.Field
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *SessionMessageResponse) UnmarshalJSON(data []byte) (err error) {
|
||||||
|
return apijson.UnmarshalRoot(data, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r sessionMessageResponseJSON) RawJSON() string {
|
||||||
|
return r.raw
|
||||||
|
}
|
||||||
|
|
||||||
type SessionMessagesResponse struct {
|
type SessionMessagesResponse struct {
|
||||||
Info Message `json:"info,required"`
|
Info Message `json:"info,required"`
|
||||||
Parts []Part `json:"parts,required"`
|
Parts []Part `json:"parts,required"`
|
||||||
|
|||||||
@@ -176,6 +176,32 @@ func TestSessionInit(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSessionMessage(t *testing.T) {
|
||||||
|
t.Skip("skipped: tests are disabled for the time being")
|
||||||
|
baseURL := "http://localhost:4010"
|
||||||
|
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
|
||||||
|
baseURL = envURL
|
||||||
|
}
|
||||||
|
if !testutil.CheckTestServer(t, baseURL) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
client := opencode.NewClient(
|
||||||
|
option.WithBaseURL(baseURL),
|
||||||
|
)
|
||||||
|
_, err := client.Session.Message(
|
||||||
|
context.TODO(),
|
||||||
|
"id",
|
||||||
|
"messageID",
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
var apierr *opencode.Error
|
||||||
|
if errors.As(err, &apierr) {
|
||||||
|
t.Log(string(apierr.DumpRequest(true)))
|
||||||
|
}
|
||||||
|
t.Fatalf("err should be nil: %s", err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestSessionMessages(t *testing.T) {
|
func TestSessionMessages(t *testing.T) {
|
||||||
t.Skip("skipped: tests are disabled for the time being")
|
t.Skip("skipped: tests are disabled for the time being")
|
||||||
baseURL := "http://localhost:4010"
|
baseURL := "http://localhost:4010"
|
||||||
|
|||||||
130
packages/sdk/go/sessionpermission.go
Normal file
130
packages/sdk/go/sessionpermission.go
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
|
||||||
|
|
||||||
|
package opencode
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/sst/opencode-sdk-go/internal/apijson"
|
||||||
|
"github.com/sst/opencode-sdk-go/internal/param"
|
||||||
|
"github.com/sst/opencode-sdk-go/internal/requestconfig"
|
||||||
|
"github.com/sst/opencode-sdk-go/option"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SessionPermissionService contains methods and other services that help with
|
||||||
|
// interacting with the opencode API.
|
||||||
|
//
|
||||||
|
// Note, unlike clients, this service does not read variables from the environment
|
||||||
|
// automatically. You should not instantiate this service directly, and instead use
|
||||||
|
// the [NewSessionPermissionService] method instead.
|
||||||
|
type SessionPermissionService struct {
|
||||||
|
Options []option.RequestOption
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewSessionPermissionService generates a new service that applies the given
|
||||||
|
// options to each request. These options are applied after the parent client's
|
||||||
|
// options (if there is one), and before any request-specific options.
|
||||||
|
func NewSessionPermissionService(opts ...option.RequestOption) (r *SessionPermissionService) {
|
||||||
|
r = &SessionPermissionService{}
|
||||||
|
r.Options = opts
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Respond to a permission request
|
||||||
|
func (r *SessionPermissionService) Respond(ctx context.Context, id string, permissionID string, body SessionPermissionRespondParams, opts ...option.RequestOption) (res *bool, err error) {
|
||||||
|
opts = append(r.Options[:], opts...)
|
||||||
|
if id == "" {
|
||||||
|
err = errors.New("missing required id parameter")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if permissionID == "" {
|
||||||
|
err = errors.New("missing required permissionID parameter")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
path := fmt.Sprintf("session/%s/permissions/%s", id, permissionID)
|
||||||
|
err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, body, &res, opts...)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
type Permission struct {
|
||||||
|
ID string `json:"id,required"`
|
||||||
|
MessageID string `json:"messageID,required"`
|
||||||
|
Metadata map[string]interface{} `json:"metadata,required"`
|
||||||
|
SessionID string `json:"sessionID,required"`
|
||||||
|
Time PermissionTime `json:"time,required"`
|
||||||
|
Title string `json:"title,required"`
|
||||||
|
Type string `json:"type,required"`
|
||||||
|
CallID string `json:"callID"`
|
||||||
|
Pattern string `json:"pattern"`
|
||||||
|
JSON permissionJSON `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// permissionJSON contains the JSON metadata for the struct [Permission]
|
||||||
|
type permissionJSON struct {
|
||||||
|
ID apijson.Field
|
||||||
|
MessageID apijson.Field
|
||||||
|
Metadata apijson.Field
|
||||||
|
SessionID apijson.Field
|
||||||
|
Time apijson.Field
|
||||||
|
Title apijson.Field
|
||||||
|
Type apijson.Field
|
||||||
|
CallID apijson.Field
|
||||||
|
Pattern apijson.Field
|
||||||
|
raw string
|
||||||
|
ExtraFields map[string]apijson.Field
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Permission) UnmarshalJSON(data []byte) (err error) {
|
||||||
|
return apijson.UnmarshalRoot(data, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r permissionJSON) RawJSON() string {
|
||||||
|
return r.raw
|
||||||
|
}
|
||||||
|
|
||||||
|
type PermissionTime struct {
|
||||||
|
Created float64 `json:"created,required"`
|
||||||
|
JSON permissionTimeJSON `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// permissionTimeJSON contains the JSON metadata for the struct [PermissionTime]
|
||||||
|
type permissionTimeJSON struct {
|
||||||
|
Created apijson.Field
|
||||||
|
raw string
|
||||||
|
ExtraFields map[string]apijson.Field
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *PermissionTime) UnmarshalJSON(data []byte) (err error) {
|
||||||
|
return apijson.UnmarshalRoot(data, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r permissionTimeJSON) RawJSON() string {
|
||||||
|
return r.raw
|
||||||
|
}
|
||||||
|
|
||||||
|
type SessionPermissionRespondParams struct {
|
||||||
|
Response param.Field[SessionPermissionRespondParamsResponse] `json:"response,required"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r SessionPermissionRespondParams) MarshalJSON() (data []byte, err error) {
|
||||||
|
return apijson.MarshalRoot(r)
|
||||||
|
}
|
||||||
|
|
||||||
|
type SessionPermissionRespondParamsResponse string
|
||||||
|
|
||||||
|
const (
|
||||||
|
SessionPermissionRespondParamsResponseOnce SessionPermissionRespondParamsResponse = "once"
|
||||||
|
SessionPermissionRespondParamsResponseAlways SessionPermissionRespondParamsResponse = "always"
|
||||||
|
SessionPermissionRespondParamsResponseReject SessionPermissionRespondParamsResponse = "reject"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (r SessionPermissionRespondParamsResponse) IsKnown() bool {
|
||||||
|
switch r {
|
||||||
|
case SessionPermissionRespondParamsResponseOnce, SessionPermissionRespondParamsResponseAlways, SessionPermissionRespondParamsResponseReject:
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
43
packages/sdk/go/sessionpermission_test.go
Normal file
43
packages/sdk/go/sessionpermission_test.go
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
|
||||||
|
|
||||||
|
package opencode_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/sst/opencode-sdk-go"
|
||||||
|
"github.com/sst/opencode-sdk-go/internal/testutil"
|
||||||
|
"github.com/sst/opencode-sdk-go/option"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestSessionPermissionRespond(t *testing.T) {
|
||||||
|
t.Skip("skipped: tests are disabled for the time being")
|
||||||
|
baseURL := "http://localhost:4010"
|
||||||
|
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
|
||||||
|
baseURL = envURL
|
||||||
|
}
|
||||||
|
if !testutil.CheckTestServer(t, baseURL) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
client := opencode.NewClient(
|
||||||
|
option.WithBaseURL(baseURL),
|
||||||
|
)
|
||||||
|
_, err := client.Session.Permissions.Respond(
|
||||||
|
context.TODO(),
|
||||||
|
"id",
|
||||||
|
"permissionID",
|
||||||
|
opencode.SessionPermissionRespondParams{
|
||||||
|
Response: opencode.F(opencode.SessionPermissionRespondParamsResponseOnce),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
var apierr *opencode.Error
|
||||||
|
if errors.As(err, &apierr) {
|
||||||
|
t.Log(string(apierr.DumpRequest(true)))
|
||||||
|
}
|
||||||
|
t.Fatalf("err should be nil: %s", err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -24,7 +24,7 @@ require (
|
|||||||
|
|
||||||
replace (
|
replace (
|
||||||
github.com/charmbracelet/x/input => ./input
|
github.com/charmbracelet/x/input => ./input
|
||||||
github.com/sst/opencode-sdk-go => ./sdk
|
github.com/sst/opencode-sdk-go => ../sdk/go
|
||||||
)
|
)
|
||||||
|
|
||||||
require golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 // indirect
|
require golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 // indirect
|
||||||
|
|||||||
@@ -469,7 +469,7 @@ func (m *messagesComponent) renderView() tea.Cmd {
|
|||||||
}
|
}
|
||||||
|
|
||||||
permission := opencode.Permission{}
|
permission := opencode.Permission{}
|
||||||
if m.app.CurrentPermission.ToolCallID == part.CallID {
|
if m.app.CurrentPermission.CallID == part.CallID {
|
||||||
permission = m.app.CurrentPermission
|
permission = m.app.CurrentPermission
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -640,7 +640,7 @@ func (m *messagesComponent) renderView() tea.Cmd {
|
|||||||
slog.Error("Failed to get message from child session", "error", err)
|
slog.Error("Failed to get message from child session", "error", err)
|
||||||
} else {
|
} else {
|
||||||
for _, part := range response.Parts {
|
for _, part := range response.Parts {
|
||||||
if part.CallID == m.app.CurrentPermission.ToolCallID {
|
if part.CallID == m.app.CurrentPermission.CallID {
|
||||||
content := renderToolDetails(
|
content := renderToolDetails(
|
||||||
m.app,
|
m.app,
|
||||||
part.AsUnion().(opencode.ToolPart),
|
part.AsUnion().(opencode.ToolPart),
|
||||||
|
|||||||
Reference in New Issue
Block a user