199 lines
4.5 KiB
TypeScript
199 lines
4.5 KiB
TypeScript
import type { MiniPermissionRequest, PermissionReply } from "./types"
|
|
import { permissionAlwaysLines, permissionOptionLabel, permissionPresentation } from "../util/permission"
|
|
import { toolPath } from "./tool"
|
|
import { monoPrefix } from "./mono"
|
|
|
|
export type PermissionStage = "permission" | "always" | "reject"
|
|
export type PermissionOption = "once" | "always" | "reject" | "confirm" | "cancel"
|
|
|
|
export type PermissionBodyState = {
|
|
requestID: string
|
|
sessionID: string
|
|
stage: PermissionStage
|
|
selected: PermissionOption
|
|
message: string
|
|
submitting: boolean
|
|
}
|
|
|
|
export type PermissionStep = {
|
|
state: PermissionBodyState
|
|
reply?: PermissionReply
|
|
}
|
|
|
|
export function createPermissionBodyState(
|
|
request: Pick<MiniPermissionRequest, "id" | "sessionID">,
|
|
): PermissionBodyState {
|
|
return {
|
|
requestID: request.id,
|
|
sessionID: request.sessionID,
|
|
stage: "permission",
|
|
selected: "once",
|
|
message: "",
|
|
submitting: false,
|
|
}
|
|
}
|
|
|
|
export function permissionOptions(stage: PermissionStage): PermissionOption[] {
|
|
if (stage === "permission") {
|
|
return ["once", "always", "reject"]
|
|
}
|
|
|
|
if (stage === "always") {
|
|
return ["confirm", "cancel"]
|
|
}
|
|
|
|
return []
|
|
}
|
|
|
|
export function permissionInfo(request: MiniPermissionRequest, directory?: string, mono = false) {
|
|
const state = request.tool?.state
|
|
const info = permissionPresentation(
|
|
{
|
|
action: request.action,
|
|
resources: request.resources,
|
|
metadata: request.metadata,
|
|
input: state?.status === "streaming" ? undefined : state?.input,
|
|
toolMetadata: state?.status === "streaming" ? undefined : state?.metadata,
|
|
},
|
|
(value) => toolPath(value, { home: true, directory }),
|
|
)
|
|
if (!mono) return info
|
|
return {
|
|
...info,
|
|
icon: monoPrefix(info.icon, true),
|
|
lines: [
|
|
...(info.diff || info.patch ? [info.diff ?? info.patch!] : []),
|
|
...info.lines.map((line) => monoPrefix(line, true)),
|
|
],
|
|
diff: undefined,
|
|
patch: undefined,
|
|
}
|
|
}
|
|
|
|
export function permissionLabel(option: PermissionOption): string {
|
|
return permissionOptionLabel(option)
|
|
}
|
|
|
|
export { permissionAlwaysLines }
|
|
|
|
function permissionReply(
|
|
sessionID: string,
|
|
requestID: string,
|
|
reply: PermissionReply["reply"],
|
|
message?: string,
|
|
): PermissionReply {
|
|
return {
|
|
sessionID,
|
|
requestID,
|
|
reply,
|
|
...(message && message.trim() ? { message: message.trim() } : {}),
|
|
}
|
|
}
|
|
|
|
export function permissionShift(
|
|
state: PermissionBodyState,
|
|
dir: -1 | 1,
|
|
list = permissionOptions(state.stage),
|
|
): PermissionBodyState {
|
|
if (list.length === 0) {
|
|
return state
|
|
}
|
|
|
|
const idx = Math.max(0, list.indexOf(state.selected))
|
|
const selected = list[(idx + dir + list.length) % list.length]
|
|
return {
|
|
...state,
|
|
selected,
|
|
}
|
|
}
|
|
|
|
export function permissionHover(state: PermissionBodyState, option: PermissionOption): PermissionBodyState {
|
|
return {
|
|
...state,
|
|
selected: option,
|
|
}
|
|
}
|
|
|
|
export function permissionRun(state: PermissionBodyState, requestID: string, option: PermissionOption): PermissionStep {
|
|
if (state.submitting) {
|
|
return { state }
|
|
}
|
|
|
|
if (state.stage === "permission") {
|
|
if (option === "always") {
|
|
return {
|
|
state: {
|
|
...state,
|
|
stage: "always",
|
|
selected: "confirm",
|
|
},
|
|
}
|
|
}
|
|
|
|
if (option === "reject") {
|
|
return {
|
|
state: {
|
|
...state,
|
|
stage: "reject",
|
|
selected: "reject",
|
|
},
|
|
}
|
|
}
|
|
|
|
return {
|
|
state,
|
|
reply: permissionReply(state.sessionID, requestID, "once"),
|
|
}
|
|
}
|
|
|
|
if (state.stage !== "always") {
|
|
return { state }
|
|
}
|
|
|
|
if (option === "cancel") {
|
|
return {
|
|
state: {
|
|
...state,
|
|
stage: "permission",
|
|
selected: "always",
|
|
},
|
|
}
|
|
}
|
|
|
|
return {
|
|
state,
|
|
reply: permissionReply(state.sessionID, requestID, "always"),
|
|
}
|
|
}
|
|
|
|
export function permissionReject(state: PermissionBodyState, requestID: string): PermissionReply | undefined {
|
|
if (state.submitting) {
|
|
return undefined
|
|
}
|
|
|
|
return permissionReply(state.sessionID, requestID, "reject", state.message)
|
|
}
|
|
|
|
export function permissionCancel(state: PermissionBodyState): PermissionBodyState {
|
|
return {
|
|
...state,
|
|
stage: "permission",
|
|
selected: "reject",
|
|
}
|
|
}
|
|
|
|
export function permissionEscape(state: PermissionBodyState): PermissionBodyState {
|
|
if (state.stage === "always") {
|
|
return {
|
|
...state,
|
|
stage: "permission",
|
|
selected: "always",
|
|
}
|
|
}
|
|
|
|
return {
|
|
...state,
|
|
stage: "reject",
|
|
selected: "reject",
|
|
}
|
|
}
|