Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 20 additions & 15 deletions packages/opencode/src/tool/skill.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { Agent } from "../agent/agent"
import { Permission } from "../permission"
import { Wildcard } from "../util/wildcard"
import { ConfigMarkdown } from "../config/markdown"
import { Config } from "../config/config"

const parameters = z.object({
name: z.string().describe("The skill identifier from available_skills (e.g., 'code-review')"),
Expand All @@ -16,15 +17,22 @@ export const SkillTool: Tool.Info<typeof parameters> = {
async init(ctx) {
const skills = await Skill.all()

// Filter skills by agent permissions if agent provided
let accessibleSkills = skills
if (ctx?.agent) {
const permissions = ctx.agent.permission.skill
accessibleSkills = skills.filter((skill) => {
const action = Wildcard.all(skill.name, permissions)
return action !== "deny"
})
}
const { accessibleSkills, permissionMap } = ctx?.agent
? skills.reduce(
(acc, skill) => {
const action = Wildcard.all(skill.name, ctx.agent!.permission.skill)
acc.permissionMap.set(skill.name, action)
if (action !== "deny") {
acc.accessibleSkills.push(skill)
}
return acc
},
{
accessibleSkills: [] as typeof skills,
permissionMap: new Map<string, typeof Config.Permission[keyof typeof Config.Permission]>(),
},
)
: { accessibleSkills: skills, permissionMap: null }

const description =
accessibleSkills.length === 0
Expand All @@ -47,20 +55,17 @@ export const SkillTool: Tool.Info<typeof parameters> = {
description,
parameters,
async execute(params, ctx) {
const agent = await Agent.get(ctx.agent)

const skill = await Skill.get(params.name)

if (!skill) {
const available = await Skill.all().then((x) => x.map((s) => s.name).join(", "))
const available = accessibleSkills.map((s) => s.name).join(", ")
throw new Error(`Skill "${params.name}" not found. Available skills: ${available || "none"}`)
}

// Check permission using Wildcard.all on the skill name
const permissions = agent.permission.skill
const action = Wildcard.all(params.name, permissions)
const action = permissionMap?.get(params.name)

if (action === "deny") {
const agent = await Agent.get(ctx.agent)
throw new Permission.RejectedError(
ctx.sessionID,
"skill",
Expand Down