feat(skills): add invocation types and parser support
Add types for skill invocation control: - SkillInvocationPolicy for user-invocable/model-invocable flags - SkillCommandSpec for command specifications - SkillCommandDispatch for tool dispatch configuration - SkillInvocationResult for resolved command results Update parser to handle frontmatter fields: - user-invocable (kebab-case, camelCase, snake_case) - disable-model-invocation - command-dispatch, command-tool, command-arg-mode Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
578c8a6534
commit
8fbd72c329
2 changed files with 121 additions and 0 deletions
|
|
@ -89,9 +89,61 @@ function validateFrontmatter(raw: Record<string, unknown>): SkillFrontmatter | n
|
|||
};
|
||||
}
|
||||
|
||||
// Parse invocation control fields
|
||||
// Support both kebab-case and camelCase for compatibility
|
||||
const userInvocableRaw =
|
||||
raw["user-invocable"] ?? raw["userInvocable"] ?? raw["user_invocable"];
|
||||
if (typeof userInvocableRaw === "boolean") {
|
||||
frontmatter.userInvocable = userInvocableRaw;
|
||||
} else if (typeof userInvocableRaw === "string") {
|
||||
frontmatter.userInvocable = parseBooleanString(userInvocableRaw);
|
||||
}
|
||||
|
||||
const disableModelRaw =
|
||||
raw["disable-model-invocation"] ??
|
||||
raw["disableModelInvocation"] ??
|
||||
raw["disable_model_invocation"];
|
||||
if (typeof disableModelRaw === "boolean") {
|
||||
frontmatter.disableModelInvocation = disableModelRaw;
|
||||
} else if (typeof disableModelRaw === "string") {
|
||||
frontmatter.disableModelInvocation = parseBooleanString(disableModelRaw);
|
||||
}
|
||||
|
||||
// Parse command dispatch fields
|
||||
const dispatchRaw =
|
||||
raw["command-dispatch"] ?? raw["commandDispatch"] ?? raw["command_dispatch"];
|
||||
if (typeof dispatchRaw === "string") {
|
||||
frontmatter.commandDispatch = dispatchRaw.trim().toLowerCase();
|
||||
}
|
||||
|
||||
const toolRaw = raw["command-tool"] ?? raw["commandTool"] ?? raw["command_tool"];
|
||||
if (typeof toolRaw === "string") {
|
||||
frontmatter.commandTool = toolRaw.trim();
|
||||
}
|
||||
|
||||
const argModeRaw =
|
||||
raw["command-arg-mode"] ?? raw["commandArgMode"] ?? raw["command_arg_mode"];
|
||||
if (typeof argModeRaw === "string") {
|
||||
frontmatter.commandArgMode = argModeRaw.trim().toLowerCase();
|
||||
}
|
||||
|
||||
return frontmatter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse boolean from string value
|
||||
*/
|
||||
function parseBooleanString(value: string): boolean | undefined {
|
||||
const normalized = value.trim().toLowerCase();
|
||||
if (normalized === "true" || normalized === "yes" || normalized === "1") {
|
||||
return true;
|
||||
}
|
||||
if (normalized === "false" || normalized === "no" || normalized === "0") {
|
||||
return false;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a SKILL.md file into a Skill object
|
||||
*
|
||||
|
|
|
|||
|
|
@ -106,6 +106,20 @@ export interface SkillFrontmatter {
|
|||
homepage?: string | undefined;
|
||||
/** Skill-specific metadata */
|
||||
metadata?: SkillMetadata | undefined;
|
||||
|
||||
// Invocation control fields
|
||||
/** Whether users can invoke via /command (default: true) */
|
||||
userInvocable?: boolean | undefined;
|
||||
/** Whether to exclude from AI system prompt (default: false) */
|
||||
disableModelInvocation?: boolean | undefined;
|
||||
|
||||
// Command dispatch fields
|
||||
/** Command dispatch mode (e.g., "tool") */
|
||||
commandDispatch?: string | undefined;
|
||||
/** Tool name for dispatch (when commandDispatch: "tool") */
|
||||
commandTool?: string | undefined;
|
||||
/** Argument mode for dispatch (default: "raw") */
|
||||
commandArgMode?: string | undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -222,6 +236,61 @@ export interface EligibilityResult {
|
|||
reasons?: string[] | undefined;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Invocation Types
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* Skill invocation policy
|
||||
* Controls how a skill can be invoked
|
||||
*/
|
||||
export interface SkillInvocationPolicy {
|
||||
/** Whether users can invoke this skill via /command (default: true) */
|
||||
userInvocable: boolean;
|
||||
/** Whether to exclude from AI's system prompt (default: false) */
|
||||
disableModelInvocation: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Command dispatch specification
|
||||
* For skills that dispatch directly to a tool
|
||||
*/
|
||||
export interface SkillCommandDispatch {
|
||||
/** Dispatch type */
|
||||
kind: "tool";
|
||||
/** Tool name to invoke */
|
||||
toolName: string;
|
||||
/** How to pass arguments (default: "raw") */
|
||||
argMode?: "raw" | undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Skill command specification
|
||||
* Represents a user-invocable skill command
|
||||
*/
|
||||
export interface SkillCommandSpec {
|
||||
/** Normalized command name (e.g., "pdf" for /pdf) */
|
||||
name: string;
|
||||
/** Original skill name/ID */
|
||||
skillId: string;
|
||||
/** Command description */
|
||||
description: string;
|
||||
/** Optional dispatch behavior */
|
||||
dispatch?: SkillCommandDispatch | undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Skill invocation result
|
||||
*/
|
||||
export interface SkillInvocationResult {
|
||||
/** The matched command */
|
||||
command: SkillCommandSpec;
|
||||
/** Arguments passed to the command */
|
||||
args?: string | undefined;
|
||||
/** The skill instructions to inject */
|
||||
instructions: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filename constant for skill definition file
|
||||
*/
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue