60 lines
2.5 KiB
TypeScript
60 lines
2.5 KiB
TypeScript
export * as ConfigPermission from "./permission"
|
|
import { Schema, SchemaGetter } from "effect"
|
|
|
|
export const Action = Schema.Literals(["ask", "allow", "deny"]).annotate({ identifier: "PermissionActionConfig" })
|
|
export type Action = Schema.Schema.Type<typeof Action>
|
|
|
|
export const Object = Schema.Record(Schema.String, Action).annotate({ identifier: "PermissionObjectConfig" })
|
|
export type Object = Schema.Schema.Type<typeof Object>
|
|
|
|
export const Rule = Schema.Union([Action, Object]).annotate({ identifier: "PermissionRuleConfig" })
|
|
export type Rule = Schema.Schema.Type<typeof Rule>
|
|
|
|
// Known permission keys get explicit types in the Effect schema for generated
|
|
// docs/types. Runtime config parsing uses Effect's `propertyOrder: "original"`
|
|
// parse option so user key order is preserved for permission precedence.
|
|
const InputObject = Schema.StructWithRest(
|
|
Schema.Struct({
|
|
read: Schema.optional(Rule),
|
|
edit: Schema.optional(Rule),
|
|
glob: Schema.optional(Rule),
|
|
grep: Schema.optional(Rule),
|
|
list: Schema.optional(Rule),
|
|
bash: Schema.optional(Rule),
|
|
task: Schema.optional(Rule),
|
|
external_directory: Schema.optional(Rule),
|
|
todowrite: Schema.optional(Action),
|
|
question: Schema.optional(Action),
|
|
webfetch: Schema.optional(Action),
|
|
websearch: Schema.optional(Action),
|
|
codesearch: Schema.optional(Action),
|
|
repo_clone: Schema.optional(Rule),
|
|
repo_overview: Schema.optional(Rule),
|
|
lsp: Schema.optional(Rule),
|
|
doom_loop: Schema.optional(Action),
|
|
skill: Schema.optional(Rule),
|
|
}),
|
|
[Schema.Record(Schema.String, Rule)],
|
|
)
|
|
|
|
// Input the user writes in config: either a single Action (shorthand for "*")
|
|
// or an object of per-target rules.
|
|
const InputSchema = Schema.Union([Action, InputObject])
|
|
|
|
// Normalise the Action shorthand into `{ "*": action }`. Object inputs pass
|
|
// through untouched.
|
|
const normalizeInput = (input: Schema.Schema.Type<typeof InputSchema>): Schema.Schema.Type<typeof InputObject> =>
|
|
typeof input === "string" ? { "*": input } : input
|
|
|
|
export const Info = InputSchema.pipe(
|
|
Schema.decodeTo(InputObject, {
|
|
decode: SchemaGetter.transform(normalizeInput),
|
|
// Not perfectly invertible (we lose whether the user originally typed an
|
|
// Action shorthand), but the object form is always a valid representation
|
|
// of the same rules.
|
|
encode: SchemaGetter.passthrough({ strict: false }),
|
|
}),
|
|
).annotate({ identifier: "PermissionConfig" })
|
|
type _Info = Schema.Schema.Type<typeof InputObject>
|
|
export type Info = { -readonly [K in keyof _Info]: _Info[K] }
|