wip: tui permissions

This commit is contained in:
adamdotdevin
2025-07-31 09:34:43 -05:00
parent e7631763f3
commit 5500698734
26 changed files with 1448 additions and 179 deletions

View File

@@ -2,6 +2,7 @@ import { App } from "../app/app"
import { z } from "zod"
import { Bus } from "../bus"
import { Log } from "../util/log"
import { Installation } from "../installation"
export namespace Permission {
const log = Log.create({ service: "permission" })
@@ -10,6 +11,8 @@ export namespace Permission {
.object({
id: z.string(),
sessionID: z.string(),
messageID: z.string(),
toolCallID: z.string().optional(),
title: z.string(),
metadata: z.record(z.any()),
time: z.object({
@@ -17,7 +20,7 @@ export namespace Permission {
}),
})
.openapi({
ref: "permission.info",
ref: "Permission",
})
export type Info = z.infer<typeof Info>
@@ -52,7 +55,7 @@ export namespace Permission {
async (state) => {
for (const pending of Object.values(state.pending)) {
for (const item of Object.values(pending)) {
item.reject(new RejectedError(item.info.sessionID, item.info.id))
item.reject(new RejectedError(item.info.sessionID, item.info.id, item.info.toolCallID))
}
}
},
@@ -61,25 +64,35 @@ export namespace Permission {
export function ask(input: {
id: Info["id"]
sessionID: Info["sessionID"]
messageID: Info["messageID"]
toolCallID?: Info["toolCallID"]
title: Info["title"]
metadata: Info["metadata"]
}) {
return
// TODO: dax, remove this when you're happy with permissions
if (!Installation.isDev()) return
const { pending, approved } = state()
log.info("asking", {
sessionID: input.sessionID,
permissionID: input.id,
messageID: input.messageID,
toolCallID: input.toolCallID,
})
if (approved[input.sessionID]?.[input.id]) {
log.info("previously approved", {
sessionID: input.sessionID,
permissionID: input.id,
messageID: input.messageID,
toolCallID: input.toolCallID,
})
return
}
const info: Info = {
id: input.id,
sessionID: input.sessionID,
messageID: input.messageID,
toolCallID: input.toolCallID,
title: input.title,
metadata: input.metadata,
time: {
@@ -93,29 +106,28 @@ export namespace Permission {
resolve,
reject,
}
setTimeout(() => {
respond({
sessionID: input.sessionID,
permissionID: input.id,
response: "always",
})
}, 1000)
// setTimeout(() => {
// respond({
// sessionID: input.sessionID,
// permissionID: input.id,
// response: "always",
// })
// }, 1000)
Bus.publish(Event.Updated, info)
})
}
export function respond(input: {
sessionID: Info["sessionID"]
permissionID: Info["id"]
response: "once" | "always" | "reject"
}) {
export const Response = z.enum(["once", "always", "reject"])
export type Response = z.infer<typeof Response>
export function respond(input: { sessionID: Info["sessionID"]; permissionID: Info["id"]; response: Response }) {
log.info("response", input)
const { pending, approved } = state()
const match = pending[input.sessionID]?.[input.permissionID]
if (!match) return
delete pending[input.sessionID][input.permissionID]
if (input.response === "reject") {
match.reject(new RejectedError(input.sessionID, input.permissionID))
match.reject(new RejectedError(input.sessionID, input.permissionID, match.info.toolCallID))
return
}
match.resolve()
@@ -129,6 +141,7 @@ export namespace Permission {
constructor(
public readonly sessionID: string,
public readonly permissionID: string,
public readonly toolCallID?: string,
) {
super(`The user rejected permission to use this functionality`)
}