fix: handle missing skill parameter in SkillTool
This commit is contained in:
32
src/tools/SkillTool/SkillTool.test.ts
Normal file
32
src/tools/SkillTool/SkillTool.test.ts
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
import { describe, expect, test } from 'bun:test'
|
||||||
|
|
||||||
|
import { SkillTool } from './SkillTool.js'
|
||||||
|
|
||||||
|
describe('SkillTool missing parameter handling', () => {
|
||||||
|
test('missing skill reaches validateInput with an actionable error', async () => {
|
||||||
|
const parsed = SkillTool.inputSchema.safeParse({})
|
||||||
|
|
||||||
|
expect(parsed.success).toBe(true)
|
||||||
|
if (!parsed.success) {
|
||||||
|
throw new Error('expected SkillTool schema to allow missing skill for custom validation')
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await SkillTool.validateInput?.(parsed.data as never, {
|
||||||
|
options: { tools: [] },
|
||||||
|
messages: [],
|
||||||
|
} as never)
|
||||||
|
|
||||||
|
expect(result).toEqual({
|
||||||
|
result: false,
|
||||||
|
message:
|
||||||
|
'Missing skill name. Pass the slash command name as the skill parameter (e.g., skill: "commit" for /commit, skill: "review-pr" for /review-pr).',
|
||||||
|
errorCode: 1,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
test('valid skill input still parses and validates', async () => {
|
||||||
|
const parsed = SkillTool.inputSchema.safeParse({ skill: 'commit' })
|
||||||
|
|
||||||
|
expect(parsed.success).toBe(true)
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -292,6 +292,7 @@ export const inputSchema = lazySchema(() =>
|
|||||||
z.object({
|
z.object({
|
||||||
skill: z
|
skill: z
|
||||||
.string()
|
.string()
|
||||||
|
.optional()
|
||||||
.describe('The skill name. E.g., "commit", "review-pr", or "pdf"'),
|
.describe('The skill name. E.g., "commit", "review-pr", or "pdf"'),
|
||||||
args: z.string().optional().describe('Optional arguments for the skill'),
|
args: z.string().optional().describe('Optional arguments for the skill'),
|
||||||
}),
|
}),
|
||||||
@@ -352,6 +353,16 @@ export const SkillTool: Tool<InputSchema, Output, Progress> = buildTool({
|
|||||||
toAutoClassifierInput: ({ skill }) => skill ?? '',
|
toAutoClassifierInput: ({ skill }) => skill ?? '',
|
||||||
|
|
||||||
async validateInput({ skill }, context): Promise<ValidationResult> {
|
async validateInput({ skill }, context): Promise<ValidationResult> {
|
||||||
|
if (!skill || typeof skill !== 'string') {
|
||||||
|
return {
|
||||||
|
result: false,
|
||||||
|
message:
|
||||||
|
'Missing skill name. Pass the slash command name as the skill parameter ' +
|
||||||
|
'(e.g., skill: "commit" for /commit, skill: "review-pr" for /review-pr).',
|
||||||
|
errorCode: 1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Skills are just skill names, no arguments
|
// Skills are just skill names, no arguments
|
||||||
const trimmed = skill.trim()
|
const trimmed = skill.trim()
|
||||||
if (!trimmed) {
|
if (!trimmed) {
|
||||||
@@ -434,7 +445,7 @@ export const SkillTool: Tool<InputSchema, Output, Progress> = buildTool({
|
|||||||
context,
|
context,
|
||||||
): Promise<PermissionDecision> {
|
): Promise<PermissionDecision> {
|
||||||
// Skills are just skill names, no arguments
|
// Skills are just skill names, no arguments
|
||||||
const trimmed = skill.trim()
|
const trimmed = skill ?? ''
|
||||||
|
|
||||||
// Remove leading slash if present (for compatibility)
|
// Remove leading slash if present (for compatibility)
|
||||||
const commandName = trimmed.startsWith('/') ? trimmed.substring(1) : trimmed
|
const commandName = trimmed.startsWith('/') ? trimmed.substring(1) : trimmed
|
||||||
@@ -592,7 +603,7 @@ export const SkillTool: Tool<InputSchema, Output, Progress> = buildTool({
|
|||||||
// - Skill is a prompt-based skill
|
// - Skill is a prompt-based skill
|
||||||
|
|
||||||
// Skills are just names, with optional arguments
|
// Skills are just names, with optional arguments
|
||||||
const trimmed = skill.trim()
|
const trimmed = skill ?? ''
|
||||||
|
|
||||||
// Remove leading slash if present (for compatibility)
|
// Remove leading slash if present (for compatibility)
|
||||||
const commandName = trimmed.startsWith('/') ? trimmed.substring(1) : trimmed
|
const commandName = trimmed.startsWith('/') ? trimmed.substring(1) : trimmed
|
||||||
|
|||||||
Reference in New Issue
Block a user