refactor(core): move v1 schemas into core (#30473)
This commit is contained in:
@@ -1,48 +1,48 @@
|
||||
import { ConfigPermission } from "@/config/permission"
|
||||
import { ConfigPermissionV1 } from "@opencode-ai/core/v1/config/permission"
|
||||
import { InstanceState } from "@/effect/instance-state"
|
||||
import * as Log from "@opencode-ai/core/util/log"
|
||||
import { Wildcard } from "@opencode-ai/core/util/wildcard"
|
||||
import { Deferred, Effect, Layer, Context } from "effect"
|
||||
import os from "os"
|
||||
import { PermissionLegacy } from "@opencode-ai/core/permission/legacy"
|
||||
import { PermissionV1 } from "@opencode-ai/core/v1/permission"
|
||||
import { EventV2Bridge } from "@/event-v2-bridge"
|
||||
import { EventV2 } from "@opencode-ai/core/event"
|
||||
|
||||
const log = Log.create({ service: "permission" })
|
||||
|
||||
export const Event = {
|
||||
Asked: EventV2.define({ type: "permission.asked", schema: PermissionLegacy.Request.fields }),
|
||||
Asked: EventV2.define({ type: "permission.asked", schema: PermissionV1.Request.fields }),
|
||||
Replied: EventV2.define({
|
||||
type: "permission.replied",
|
||||
schema: {
|
||||
sessionID: PermissionLegacy.Request.fields.sessionID,
|
||||
requestID: PermissionLegacy.ID,
|
||||
reply: PermissionLegacy.Reply,
|
||||
sessionID: PermissionV1.Request.fields.sessionID,
|
||||
requestID: PermissionV1.ID,
|
||||
reply: PermissionV1.Reply,
|
||||
},
|
||||
}),
|
||||
}
|
||||
|
||||
export interface Interface {
|
||||
readonly ask: (input: PermissionLegacy.AskInput) => Effect.Effect<void, PermissionLegacy.Error>
|
||||
readonly reply: (input: PermissionLegacy.ReplyInput) => Effect.Effect<void, PermissionLegacy.NotFoundError>
|
||||
readonly list: () => Effect.Effect<ReadonlyArray<PermissionLegacy.Request>>
|
||||
readonly ask: (input: PermissionV1.AskInput) => Effect.Effect<void, PermissionV1.Error>
|
||||
readonly reply: (input: PermissionV1.ReplyInput) => Effect.Effect<void, PermissionV1.NotFoundError>
|
||||
readonly list: () => Effect.Effect<ReadonlyArray<PermissionV1.Request>>
|
||||
}
|
||||
|
||||
interface PendingEntry {
|
||||
info: PermissionLegacy.Request
|
||||
deferred: Deferred.Deferred<void, PermissionLegacy.RejectedError | PermissionLegacy.CorrectedError>
|
||||
info: PermissionV1.Request
|
||||
deferred: Deferred.Deferred<void, PermissionV1.RejectedError | PermissionV1.CorrectedError>
|
||||
}
|
||||
|
||||
interface State {
|
||||
pending: Map<PermissionLegacy.ID, PendingEntry>
|
||||
approved: PermissionLegacy.Rule[]
|
||||
pending: Map<PermissionV1.ID, PendingEntry>
|
||||
approved: PermissionV1.Rule[]
|
||||
}
|
||||
|
||||
export function evaluate(
|
||||
permission: string,
|
||||
pattern: string,
|
||||
...rulesets: PermissionLegacy.Ruleset[]
|
||||
): PermissionLegacy.Rule {
|
||||
...rulesets: PermissionV1.Ruleset[]
|
||||
): PermissionV1.Rule {
|
||||
return (
|
||||
rulesets
|
||||
.flat()
|
||||
@@ -64,14 +64,14 @@ export const layer = Layer.effect(
|
||||
Effect.fn("Permission.state")(function* (ctx) {
|
||||
void ctx
|
||||
const state = {
|
||||
pending: new Map<PermissionLegacy.ID, PendingEntry>(),
|
||||
pending: new Map<PermissionV1.ID, PendingEntry>(),
|
||||
approved: [],
|
||||
}
|
||||
|
||||
yield* Effect.addFinalizer(() =>
|
||||
Effect.gen(function* () {
|
||||
for (const item of state.pending.values()) {
|
||||
yield* Deferred.fail(item.deferred, new PermissionLegacy.RejectedError())
|
||||
yield* Deferred.fail(item.deferred, new PermissionV1.RejectedError())
|
||||
}
|
||||
state.pending.clear()
|
||||
}),
|
||||
@@ -81,7 +81,7 @@ export const layer = Layer.effect(
|
||||
}),
|
||||
)
|
||||
|
||||
const ask = Effect.fn("Permission.ask")(function* (input: PermissionLegacy.AskInput) {
|
||||
const ask = Effect.fn("Permission.ask")(function* (input: PermissionV1.AskInput) {
|
||||
const { approved, pending } = yield* InstanceState.get(state)
|
||||
const { ruleset, ...request } = input
|
||||
let needsAsk = false
|
||||
@@ -90,7 +90,7 @@ export const layer = Layer.effect(
|
||||
const rule = evaluate(request.permission, pattern, ruleset, approved)
|
||||
log.info("evaluated", { permission: request.permission, pattern, action: rule })
|
||||
if (rule.action === "deny") {
|
||||
return yield* new PermissionLegacy.DeniedError({
|
||||
return yield* new PermissionV1.DeniedError({
|
||||
ruleset: ruleset.filter((rule) => Wildcard.match(request.permission, rule.permission)),
|
||||
})
|
||||
}
|
||||
@@ -100,8 +100,8 @@ export const layer = Layer.effect(
|
||||
|
||||
if (!needsAsk) return
|
||||
|
||||
const id = request.id ?? PermissionLegacy.ID.ascending()
|
||||
const info: PermissionLegacy.Request = {
|
||||
const id = request.id ?? PermissionV1.ID.ascending()
|
||||
const info: PermissionV1.Request = {
|
||||
id,
|
||||
sessionID: request.sessionID,
|
||||
permission: request.permission,
|
||||
@@ -112,7 +112,7 @@ export const layer = Layer.effect(
|
||||
}
|
||||
log.info("asking", { id, permission: info.permission, patterns: info.patterns })
|
||||
|
||||
const deferred = yield* Deferred.make<void, PermissionLegacy.RejectedError | PermissionLegacy.CorrectedError>()
|
||||
const deferred = yield* Deferred.make<void, PermissionV1.RejectedError | PermissionV1.CorrectedError>()
|
||||
pending.set(id, { info, deferred })
|
||||
yield* events.publish(Event.Asked, info)
|
||||
return yield* Effect.ensuring(
|
||||
@@ -123,10 +123,10 @@ export const layer = Layer.effect(
|
||||
)
|
||||
})
|
||||
|
||||
const reply = Effect.fn("Permission.reply")(function* (input: PermissionLegacy.ReplyInput) {
|
||||
const reply = Effect.fn("Permission.reply")(function* (input: PermissionV1.ReplyInput) {
|
||||
const { approved, pending } = yield* InstanceState.get(state)
|
||||
const existing = pending.get(input.requestID)
|
||||
if (!existing) return yield* new PermissionLegacy.NotFoundError({ requestID: input.requestID })
|
||||
if (!existing) return yield* new PermissionV1.NotFoundError({ requestID: input.requestID })
|
||||
|
||||
pending.delete(input.requestID)
|
||||
yield* events.publish(Event.Replied, {
|
||||
@@ -139,8 +139,8 @@ export const layer = Layer.effect(
|
||||
yield* Deferred.fail(
|
||||
existing.deferred,
|
||||
input.message
|
||||
? new PermissionLegacy.CorrectedError({ feedback: input.message })
|
||||
: new PermissionLegacy.RejectedError(),
|
||||
? new PermissionV1.CorrectedError({ feedback: input.message })
|
||||
: new PermissionV1.RejectedError(),
|
||||
)
|
||||
|
||||
for (const [id, item] of pending.entries()) {
|
||||
@@ -151,7 +151,7 @@ export const layer = Layer.effect(
|
||||
requestID: item.info.id,
|
||||
reply: "reject",
|
||||
})
|
||||
yield* Deferred.fail(item.deferred, new PermissionLegacy.RejectedError())
|
||||
yield* Deferred.fail(item.deferred, new PermissionV1.RejectedError())
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -200,8 +200,8 @@ function expand(pattern: string): string {
|
||||
return pattern
|
||||
}
|
||||
|
||||
export function fromConfig(permission: ConfigPermission.Info) {
|
||||
const ruleset: PermissionLegacy.Rule[] = []
|
||||
export function fromConfig(permission: ConfigPermissionV1.Info) {
|
||||
const ruleset: PermissionV1.Rule[] = []
|
||||
for (const [key, value] of Object.entries(permission)) {
|
||||
if (typeof value === "string") {
|
||||
ruleset.push({ permission: key, action: value, pattern: "*" })
|
||||
@@ -214,11 +214,11 @@ export function fromConfig(permission: ConfigPermission.Info) {
|
||||
return ruleset
|
||||
}
|
||||
|
||||
export function merge(...rulesets: PermissionLegacy.Ruleset[]): PermissionLegacy.Rule[] {
|
||||
export function merge(...rulesets: PermissionV1.Ruleset[]): PermissionV1.Rule[] {
|
||||
return rulesets.flat()
|
||||
}
|
||||
|
||||
export function disabled(tools: string[], ruleset: PermissionLegacy.Ruleset): Set<string> {
|
||||
export function disabled(tools: string[], ruleset: PermissionV1.Ruleset): Set<string> {
|
||||
const edits = ["edit", "write", "apply_patch"]
|
||||
return new Set(
|
||||
tools.filter((tool) => {
|
||||
|
||||
Reference in New Issue
Block a user