diff --git a/packages/opencode/src/config/permission.ts b/packages/opencode/src/config/permission.ts index 909112c7c5..a7390e9534 100644 --- a/packages/opencode/src/config/permission.ts +++ b/packages/opencode/src/config/permission.ts @@ -53,17 +53,34 @@ const InputSchema = Schema.Union([Action, InputObject]) const normalizeInput = (input: Schema.Schema.Type): Schema.Schema.Type => typeof input === "string" ? { "*": input } : input -const ACTION_ONLY = new Set(["todowrite", "question", "webfetch", "websearch", "codesearch", "doom_loop"]) - const InfoZod = z - .union([zod(Action), z.record(z.string(), z.union([zod(Action), z.record(z.string(), zod(Action))]))]) + .union([ + zod(Action), + z.intersection( + z.record(z.string(), zod(Rule)), + z + .object({ + read: zod(Rule).optional(), + edit: zod(Rule).optional(), + glob: zod(Rule).optional(), + grep: zod(Rule).optional(), + list: zod(Rule).optional(), + bash: zod(Rule).optional(), + task: zod(Rule).optional(), + external_directory: zod(Rule).optional(), + todowrite: zod(Action).optional(), + question: zod(Action).optional(), + webfetch: zod(Action).optional(), + websearch: zod(Action).optional(), + codesearch: zod(Action).optional(), + lsp: zod(Rule).optional(), + doom_loop: zod(Action).optional(), + skill: zod(Rule).optional(), + }) + .catchall(zod(Rule)), + ), + ]) .transform(normalizeInput) - .superRefine((input, ctx) => { - for (const [key, value] of globalThis.Object.entries(input)) { - if (!ACTION_ONLY.has(key) || typeof value === "string") continue - ctx.addIssue({ code: "custom", message: `${key} must be a permission action`, path: [key] }) - } - }) export const Info = InputSchema.pipe( Schema.decodeTo(InputObject, { diff --git a/packages/sdk/js/src/v2/gen/types.gen.ts b/packages/sdk/js/src/v2/gen/types.gen.ts index 51a79d99da..0ad88bb50c 100644 --- a/packages/sdk/js/src/v2/gen/types.gen.ts +++ b/packages/sdk/js/src/v2/gen/types.gen.ts @@ -1198,15 +1198,35 @@ export type ServerConfig = { export type PermissionActionConfig = "ask" | "allow" | "deny" +export type PermissionObjectConfig = { + [key: string]: PermissionActionConfig +} + +export type PermissionRuleConfig = PermissionActionConfig | PermissionObjectConfig + export type PermissionConfig = | PermissionActionConfig - | { - [key: string]: - | PermissionActionConfig - | { - [key: string]: PermissionActionConfig - } - } + | ({ + [key: string]: PermissionRuleConfig + } & { + read?: PermissionRuleConfig + edit?: PermissionRuleConfig + glob?: PermissionRuleConfig + grep?: PermissionRuleConfig + list?: PermissionRuleConfig + bash?: PermissionRuleConfig + task?: PermissionRuleConfig + external_directory?: PermissionRuleConfig + todowrite?: PermissionActionConfig + question?: PermissionActionConfig + webfetch?: PermissionActionConfig + websearch?: PermissionActionConfig + codesearch?: PermissionActionConfig + lsp?: PermissionRuleConfig + doom_loop?: PermissionActionConfig + skill?: PermissionRuleConfig + [key: string]: PermissionRuleConfig | PermissionActionConfig | undefined + }) export type AgentConfig = { model?: string diff --git a/packages/sdk/openapi.json b/packages/sdk/openapi.json index cbb9aaecc5..7be58195ba 100644 --- a/packages/sdk/openapi.json +++ b/packages/sdk/openapi.json @@ -10926,32 +10926,98 @@ "type": "string", "enum": ["ask", "allow", "deny"] }, + "PermissionObjectConfig": { + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": { + "$ref": "#/components/schemas/PermissionActionConfig" + } + }, + "PermissionRuleConfig": { + "anyOf": [ + { + "$ref": "#/components/schemas/PermissionActionConfig" + }, + { + "$ref": "#/components/schemas/PermissionObjectConfig" + } + ] + }, "PermissionConfig": { "anyOf": [ { "$ref": "#/components/schemas/PermissionActionConfig" }, { - "type": "object", - "propertyNames": { - "type": "string" - }, - "additionalProperties": { - "anyOf": [ - { - "$ref": "#/components/schemas/PermissionActionConfig" + "allOf": [ + { + "type": "object", + "propertyNames": { + "type": "string" }, - { - "type": "object", - "propertyNames": { - "type": "string" - }, - "additionalProperties": { - "$ref": "#/components/schemas/PermissionActionConfig" - } + "additionalProperties": { + "$ref": "#/components/schemas/PermissionRuleConfig" } - ] - } + }, + { + "type": "object", + "properties": { + "read": { + "$ref": "#/components/schemas/PermissionRuleConfig" + }, + "edit": { + "$ref": "#/components/schemas/PermissionRuleConfig" + }, + "glob": { + "$ref": "#/components/schemas/PermissionRuleConfig" + }, + "grep": { + "$ref": "#/components/schemas/PermissionRuleConfig" + }, + "list": { + "$ref": "#/components/schemas/PermissionRuleConfig" + }, + "bash": { + "$ref": "#/components/schemas/PermissionRuleConfig" + }, + "task": { + "$ref": "#/components/schemas/PermissionRuleConfig" + }, + "external_directory": { + "$ref": "#/components/schemas/PermissionRuleConfig" + }, + "todowrite": { + "$ref": "#/components/schemas/PermissionActionConfig" + }, + "question": { + "$ref": "#/components/schemas/PermissionActionConfig" + }, + "webfetch": { + "$ref": "#/components/schemas/PermissionActionConfig" + }, + "websearch": { + "$ref": "#/components/schemas/PermissionActionConfig" + }, + "codesearch": { + "$ref": "#/components/schemas/PermissionActionConfig" + }, + "lsp": { + "$ref": "#/components/schemas/PermissionRuleConfig" + }, + "doom_loop": { + "$ref": "#/components/schemas/PermissionActionConfig" + }, + "skill": { + "$ref": "#/components/schemas/PermissionRuleConfig" + } + }, + "additionalProperties": { + "$ref": "#/components/schemas/PermissionRuleConfig" + } + } + ] } ] },