From cdfaea5cedf88383ade635ec08cef335a35d3abf Mon Sep 17 00:00:00 2001 From: gnanam1990 Date: Tue, 7 Apr 2026 20:23:36 +0530 Subject: [PATCH] fix: handle missing skill parameter in SkillTool --- src/tools/SkillTool/SkillTool.test.ts | 32 +++++++++++++++++++++++++++ src/tools/SkillTool/SkillTool.ts | 15 +++++++++++-- 2 files changed, 45 insertions(+), 2 deletions(-) create mode 100644 src/tools/SkillTool/SkillTool.test.ts diff --git a/src/tools/SkillTool/SkillTool.test.ts b/src/tools/SkillTool/SkillTool.test.ts new file mode 100644 index 00000000..543327a9 --- /dev/null +++ b/src/tools/SkillTool/SkillTool.test.ts @@ -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) + }) +}) diff --git a/src/tools/SkillTool/SkillTool.ts b/src/tools/SkillTool/SkillTool.ts index befde568..821a7534 100644 --- a/src/tools/SkillTool/SkillTool.ts +++ b/src/tools/SkillTool/SkillTool.ts @@ -292,6 +292,7 @@ export const inputSchema = lazySchema(() => z.object({ skill: z .string() + .optional() .describe('The skill name. E.g., "commit", "review-pr", or "pdf"'), args: z.string().optional().describe('Optional arguments for the skill'), }), @@ -352,6 +353,16 @@ export const SkillTool: Tool = buildTool({ toAutoClassifierInput: ({ skill }) => skill ?? '', async validateInput({ skill }, context): Promise { + 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 const trimmed = skill.trim() if (!trimmed) { @@ -434,7 +445,7 @@ export const SkillTool: Tool = buildTool({ context, ): Promise { // Skills are just skill names, no arguments - const trimmed = skill.trim() + const trimmed = skill ?? '' // Remove leading slash if present (for compatibility) const commandName = trimmed.startsWith('/') ? trimmed.substring(1) : trimmed @@ -592,7 +603,7 @@ export const SkillTool: Tool = buildTool({ // - Skill is a prompt-based skill // Skills are just names, with optional arguments - const trimmed = skill.trim() + const trimmed = skill ?? '' // Remove leading slash if present (for compatibility) const commandName = trimmed.startsWith('/') ? trimmed.substring(1) : trimmed